├── .gitignore ├── Assets └── screenshot.png ├── LICENSE ├── Podfile ├── Podfile.lock ├── Pods ├── Local Podspecs │ └── PopupDialog.podspec.json ├── Manifest.lock ├── Pods.xcodeproj │ └── project.pbxproj ├── PopupDialog │ ├── LICENSE │ ├── PopupDialog │ │ └── Classes │ │ │ ├── FXBlurView.h │ │ │ ├── FXBlurView.m │ │ │ ├── InteractiveTransition.swift │ │ │ ├── PopupDialog+Keyboard.swift │ │ │ ├── PopupDialog.swift │ │ │ ├── PopupDialogButton.swift │ │ │ ├── PopupDialogContainerView.swift │ │ │ ├── PopupDialogDefaultButtons.swift │ │ │ ├── PopupDialogDefaultView.swift │ │ │ ├── PopupDialogDefaultViewController.swift │ │ │ ├── PopupDialogOverlayView.swift │ │ │ ├── PresentationController.swift │ │ │ ├── PresentationManager.swift │ │ │ ├── TZStackView │ │ │ ├── TZSpacerView.swift │ │ │ ├── TZStackView.swift │ │ │ ├── TZStackViewAlignment.swift │ │ │ └── TZStackViewDistribution.swift │ │ │ ├── TransitionAnimations.swift │ │ │ ├── TransitionAnimator.swift │ │ │ ├── UIImageView+Calculations.swift │ │ │ ├── UIView+Animations.swift │ │ │ └── UIViewController+Visibility.swift │ └── README.md └── Target Support Files │ ├── Pods-PopupDialogTableView │ ├── Info.plist │ ├── Pods-PopupDialogTableView-acknowledgements.markdown │ ├── Pods-PopupDialogTableView-acknowledgements.plist │ ├── Pods-PopupDialogTableView-dummy.m │ ├── Pods-PopupDialogTableView-frameworks.sh │ ├── Pods-PopupDialogTableView-resources.sh │ ├── Pods-PopupDialogTableView-umbrella.h │ ├── Pods-PopupDialogTableView.debug.xcconfig │ ├── Pods-PopupDialogTableView.modulemap │ └── Pods-PopupDialogTableView.release.xcconfig │ └── PopupDialog │ ├── Info.plist │ ├── PopupDialog-dummy.m │ ├── PopupDialog-prefix.pch │ ├── PopupDialog-umbrella.h │ ├── PopupDialog.modulemap │ └── PopupDialog.xcconfig ├── PopupDialogTableView.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── mwfire.xcuserdatad │ └── xcschemes │ ├── PopupDialogTableView.xcscheme │ └── xcschememanagement.plist ├── PopupDialogTableView.xcworkspace └── contents.xcworkspacedata ├── PopupDialogTableView ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── PopupTableView.swift ├── PopupTableViewCell.swift ├── PopupTableViewController.swift └── ViewController.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/xcode,swift 3 | 4 | ### Xcode ### 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | 24 | ## Other 25 | *.moved-aside 26 | *.xccheckout 27 | *.xcscmblueprint 28 | 29 | 30 | ### Swift ### 31 | # Xcode 32 | # 33 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 34 | 35 | ## Build generated 36 | 37 | ## Various settings 38 | 39 | ## Other 40 | *.xcuserstate 41 | 42 | ## Obj-C/Swift specific 43 | *.hmap 44 | *.ipa 45 | *.dSYM.zip 46 | *.dSYM 47 | 48 | ## Playgrounds 49 | timeline.xctimeline 50 | playground.xcworkspace 51 | 52 | # Swift Package Manager 53 | # 54 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 55 | # Packages/ 56 | .build/ 57 | 58 | # CocoaPods 59 | # 60 | # We recommend against adding the Pods directory to your .gitignore. However 61 | # you should judge for yourself, the pros and cons are mentioned at: 62 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 63 | # 64 | # Pods/ 65 | 66 | # Carthage 67 | # 68 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 69 | # Carthage/Checkouts 70 | 71 | Carthage/Build 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 76 | # screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots 83 | fastlane/test_output 84 | 85 | # End of https://www.gitignore.io/api/xcode,swift -------------------------------------------------------------------------------- /Assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mwfire/PopupDialogCustomExample/a827ba36da9411114bb97ca3a77bcbabc11647d8/Assets/screenshot.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Martin Wildfeuer (http://www.mwfire.de) 2 | Author - Martin Wildfeuer (http://www.mwfire.de) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'PopupDialogTableView' 4 | pod 'PopupDialog' 5 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PopupDialog (0.5.3) 3 | 4 | DEPENDENCIES: 5 | - PopupDialog 6 | 7 | SPEC CHECKSUMS: 8 | PopupDialog: 533dd564f8781633375505b9fbd406f8f146ccc9 9 | 10 | PODFILE CHECKSUM: f004dce7c3029e49c4dcb2873e3265e0edf6a0b0 11 | 12 | COCOAPODS: 1.1.1 13 | -------------------------------------------------------------------------------- /Pods/Local Podspecs/PopupDialog.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "PopupDialog", 3 | "version": "0.5.2", 4 | "summary": "A simple custom popup dialog view controller", 5 | "homepage": "https://github.com/orderella/PopupDialog", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Martin Wildfeuer": "mwfire@mwfire.de" 12 | }, 13 | "source": { 14 | "git": "https://github.com/orderella/PopupDialog.git", 15 | "tag": "0.5.2" 16 | }, 17 | "social_media_url": "https://twitter.com/orderella", 18 | "platforms": { 19 | "ios": "8.0" 20 | }, 21 | "source_files": "PopupDialog/Classes/**/*" 22 | } 23 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - PopupDialog (0.5.3) 3 | 4 | DEPENDENCIES: 5 | - PopupDialog 6 | 7 | SPEC CHECKSUMS: 8 | PopupDialog: 533dd564f8781633375505b9fbd406f8f146ccc9 9 | 10 | PODFILE CHECKSUM: f004dce7c3029e49c4dcb2873e3265e0edf6a0b0 11 | 12 | COCOAPODS: 1.1.1 13 | -------------------------------------------------------------------------------- /Pods/PopupDialog/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 2 | Author - Martin Wildfeuer (http://www.mwfire.de) 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/FXBlurView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FXBlurView.h 3 | // 4 | // Version 1.6.4 5 | // 6 | // Created by Nick Lockwood on 25/08/2013. 7 | // Copyright (c) 2013 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/FXBlurView 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | 34 | #import 35 | #import 36 | #import 37 | 38 | 39 | #pragma GCC diagnostic push 40 | #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" 41 | 42 | 43 | #import 44 | #undef weak_ref 45 | #if __has_feature(objc_arc) && __has_feature(objc_arc_weak) 46 | #define weak_ref weak 47 | #else 48 | #define weak_ref unsafe_unretained 49 | #endif 50 | 51 | 52 | @interface UIImage (FXBlurView) 53 | 54 | - (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor; 55 | 56 | @end 57 | 58 | 59 | @interface FXBlurView : UIView 60 | 61 | + (void)setBlurEnabled:(BOOL)blurEnabled; 62 | + (void)setUpdatesEnabled; 63 | + (void)setUpdatesDisabled; 64 | 65 | @property (nonatomic, getter = isBlurEnabled) BOOL blurEnabled; 66 | @property (nonatomic, getter = isDynamic) BOOL dynamic; 67 | @property (nonatomic, assign) NSUInteger iterations; 68 | @property (nonatomic, assign) NSTimeInterval updateInterval; 69 | @property (nonatomic, assign) CGFloat blurRadius; 70 | @property (nonatomic, strong) UIColor *tintColor; 71 | @property (nonatomic, weak_ref) IBOutlet UIView *underlyingView; 72 | 73 | - (void)updateAsynchronously:(BOOL)async completion:(void (^)())completion; 74 | 75 | - (void)clearImage; 76 | 77 | @end 78 | 79 | 80 | #pragma GCC diagnostic pop 81 | 82 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/FXBlurView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FXBlurView.m 3 | // 4 | // Version 1.6.4 5 | // 6 | // Created by Nick Lockwood on 25/08/2013. 7 | // Copyright (c) 2013 Charcoal Design 8 | // 9 | // Distributed under the permissive zlib License 10 | // Get the latest version from here: 11 | // 12 | // https://github.com/nicklockwood/FXBlurView 13 | // 14 | // This software is provided 'as-is', without any express or implied 15 | // warranty. In no event will the authors be held liable for any damages 16 | // arising from the use of this software. 17 | // 18 | // Permission is granted to anyone to use this software for any purpose, 19 | // including commercial applications, and to alter it and redistribute it 20 | // freely, subject to the following restrictions: 21 | // 22 | // 1. The origin of this software must not be misrepresented; you must not 23 | // claim that you wrote the original software. If you use this software 24 | // in a product, an acknowledgment in the product documentation would be 25 | // appreciated but is not required. 26 | // 27 | // 2. Altered source versions must be plainly marked as such, and must not be 28 | // misrepresented as being the original software. 29 | // 30 | // 3. This notice may not be removed or altered from any source distribution. 31 | // 32 | 33 | 34 | #import "FXBlurView.h" 35 | #import 36 | 37 | 38 | #pragma GCC diagnostic ignored "-Wobjc-missing-property-synthesis" 39 | #pragma GCC diagnostic ignored "-Wdirect-ivar-access" 40 | #pragma GCC diagnostic ignored "-Wgnu" 41 | 42 | 43 | #import 44 | #if !__has_feature(objc_arc) 45 | #error This class requires automatic reference counting 46 | #endif 47 | 48 | 49 | @implementation UIImage (FXBlurView) 50 | 51 | - (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor 52 | { 53 | //image must be nonzero size 54 | if (floorf(self.size.width) * floorf(self.size.height) <= 0.0f) return self; 55 | 56 | //boxsize must be an odd integer 57 | uint32_t boxSize = (uint32_t)(radius * self.scale); 58 | if (boxSize % 2 == 0) boxSize ++; 59 | 60 | //create image buffers 61 | CGImageRef imageRef = self.CGImage; 62 | 63 | //convert to ARGB if it isn't 64 | if (CGImageGetBitsPerPixel(imageRef) != 32 || 65 | CGImageGetBitsPerComponent(imageRef) != 8 || 66 | !((CGImageGetBitmapInfo(imageRef) & kCGBitmapAlphaInfoMask))) 67 | { 68 | UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale); 69 | [self drawAtPoint:CGPointZero]; 70 | imageRef = UIGraphicsGetImageFromCurrentImageContext().CGImage; 71 | UIGraphicsEndImageContext(); 72 | } 73 | 74 | vImage_Buffer buffer1, buffer2; 75 | buffer1.width = buffer2.width = CGImageGetWidth(imageRef); 76 | buffer1.height = buffer2.height = CGImageGetHeight(imageRef); 77 | buffer1.rowBytes = buffer2.rowBytes = CGImageGetBytesPerRow(imageRef); 78 | size_t bytes = buffer1.rowBytes * buffer1.height; 79 | buffer1.data = malloc(bytes); 80 | buffer2.data = malloc(bytes); 81 | 82 | //create temp buffer 83 | void *tempBuffer = malloc((size_t)vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, NULL, 0, 0, boxSize, boxSize, 84 | NULL, kvImageEdgeExtend + kvImageGetTempBufferSize)); 85 | 86 | //copy image data 87 | CFDataRef dataSource = CGDataProviderCopyData(CGImageGetDataProvider(imageRef)); 88 | memcpy(buffer1.data, CFDataGetBytePtr(dataSource), bytes); 89 | CFRelease(dataSource); 90 | 91 | for (NSUInteger i = 0; i < iterations; i++) 92 | { 93 | //perform blur 94 | vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend); 95 | 96 | //swap buffers 97 | void *temp = buffer1.data; 98 | buffer1.data = buffer2.data; 99 | buffer2.data = temp; 100 | } 101 | 102 | //free buffers 103 | free(buffer2.data); 104 | free(tempBuffer); 105 | 106 | //create image context from buffer 107 | CGContextRef ctx = CGBitmapContextCreate(buffer1.data, buffer1.width, buffer1.height, 108 | 8, buffer1.rowBytes, CGImageGetColorSpace(imageRef), 109 | CGImageGetBitmapInfo(imageRef)); 110 | 111 | //apply tint 112 | if (tintColor && CGColorGetAlpha(tintColor.CGColor) > 0.0f) 113 | { 114 | CGContextSetFillColorWithColor(ctx, [tintColor colorWithAlphaComponent:0.25].CGColor); 115 | CGContextSetBlendMode(ctx, kCGBlendModePlusLighter); 116 | CGContextFillRect(ctx, CGRectMake(0, 0, buffer1.width, buffer1.height)); 117 | } 118 | 119 | //create image from context 120 | imageRef = CGBitmapContextCreateImage(ctx); 121 | UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; 122 | CGImageRelease(imageRef); 123 | CGContextRelease(ctx); 124 | free(buffer1.data); 125 | return image; 126 | } 127 | 128 | @end 129 | 130 | 131 | @interface FXBlurScheduler : NSObject 132 | 133 | @property (nonatomic, strong) NSMutableArray *views; 134 | @property (nonatomic, assign) NSUInteger viewIndex; 135 | @property (nonatomic, assign) NSUInteger updatesEnabled; 136 | @property (nonatomic, assign) BOOL blurEnabled; 137 | @property (nonatomic, assign) BOOL updating; 138 | 139 | @end 140 | 141 | 142 | @interface FXBlurLayer: CALayer 143 | 144 | @property (nonatomic, assign) CGFloat blurRadius; 145 | 146 | @end 147 | 148 | 149 | @implementation FXBlurLayer 150 | 151 | @dynamic blurRadius; 152 | 153 | + (BOOL)needsDisplayForKey:(NSString *)key 154 | { 155 | if ([@[@"blurRadius", @"bounds", @"position"] containsObject:key]) 156 | { 157 | return YES; 158 | } 159 | return [super needsDisplayForKey:key]; 160 | } 161 | 162 | @end 163 | 164 | 165 | @interface FXBlurView () 166 | 167 | @property (nonatomic, assign) BOOL iterationsSet; 168 | @property (nonatomic, assign) BOOL blurRadiusSet; 169 | @property (nonatomic, assign) BOOL dynamicSet; 170 | @property (nonatomic, assign) BOOL blurEnabledSet; 171 | @property (nonatomic, strong) NSDate *lastUpdate; 172 | @property (nonatomic, assign) BOOL needsDrawViewHierarchy; 173 | 174 | - (UIImage *)snapshotOfUnderlyingView; 175 | - (BOOL)shouldUpdate; 176 | 177 | @end 178 | 179 | 180 | @implementation FXBlurScheduler 181 | 182 | + (instancetype)sharedInstance 183 | { 184 | static FXBlurScheduler *sharedInstance = nil; 185 | if (!sharedInstance) 186 | { 187 | sharedInstance = [[FXBlurScheduler alloc] init]; 188 | } 189 | return sharedInstance; 190 | } 191 | 192 | - (instancetype)init 193 | { 194 | if ((self = [super init])) 195 | { 196 | _updatesEnabled = 1; 197 | _blurEnabled = YES; 198 | _views = [[NSMutableArray alloc] init]; 199 | } 200 | return self; 201 | } 202 | 203 | - (void)setBlurEnabled:(BOOL)blurEnabled 204 | { 205 | _blurEnabled = blurEnabled; 206 | if (blurEnabled) 207 | { 208 | for (FXBlurView *view in self.views) 209 | { 210 | [view setNeedsDisplay]; 211 | } 212 | [self updateAsynchronously]; 213 | } 214 | } 215 | 216 | - (void)setUpdatesEnabled 217 | { 218 | _updatesEnabled ++; 219 | [self updateAsynchronously]; 220 | } 221 | 222 | - (void)setUpdatesDisabled 223 | { 224 | _updatesEnabled --; 225 | } 226 | 227 | - (void)addView:(FXBlurView *)view 228 | { 229 | if (![self.views containsObject:view]) 230 | { 231 | [self.views addObject:view]; 232 | [self updateAsynchronously]; 233 | } 234 | } 235 | 236 | - (void)removeView:(FXBlurView *)view 237 | { 238 | NSUInteger index = [self.views indexOfObject:view]; 239 | if (index != NSNotFound) 240 | { 241 | if (index <= self.viewIndex) 242 | { 243 | self.viewIndex --; 244 | } 245 | [self.views removeObjectAtIndex:index]; 246 | } 247 | } 248 | 249 | - (void)updateAsynchronously 250 | { 251 | if (self.blurEnabled && !self.updating && self.updatesEnabled > 0 && [self.views count]) 252 | { 253 | NSTimeInterval timeUntilNextUpdate = 1.0 / 60; 254 | 255 | //loop through until we find a view that's ready to be drawn 256 | self.viewIndex = self.viewIndex % [self.views count]; 257 | for (NSUInteger i = self.viewIndex; i < [self.views count]; i++) 258 | { 259 | FXBlurView *view = self.views[i]; 260 | if (view.dynamic && !view.hidden && view.window && [view shouldUpdate]) 261 | { 262 | NSTimeInterval nextUpdate = [view.lastUpdate timeIntervalSinceNow] + view.updateInterval; 263 | if (!view.lastUpdate || nextUpdate <= 0) 264 | { 265 | self.updating = YES; 266 | [view updateAsynchronously:YES completion:^{ 267 | 268 | //render next view 269 | self.updating = NO; 270 | self.viewIndex = i + 1; 271 | [self updateAsynchronously]; 272 | }]; 273 | return; 274 | } 275 | else 276 | { 277 | timeUntilNextUpdate = MIN(timeUntilNextUpdate, nextUpdate); 278 | } 279 | } 280 | } 281 | 282 | //try again, delaying until the time when the next view needs an update. 283 | self.viewIndex = 0; 284 | [self performSelector:@selector(updateAsynchronously) 285 | withObject:nil 286 | afterDelay:timeUntilNextUpdate 287 | inModes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]]; 288 | } 289 | } 290 | 291 | @end 292 | 293 | 294 | @implementation FXBlurView 295 | 296 | @synthesize underlyingView = _underlyingView; 297 | 298 | + (void)setBlurEnabled:(BOOL)blurEnabled 299 | { 300 | [FXBlurScheduler sharedInstance].blurEnabled = blurEnabled; 301 | } 302 | 303 | + (void)setUpdatesEnabled 304 | { 305 | [[FXBlurScheduler sharedInstance] setUpdatesEnabled]; 306 | } 307 | 308 | + (void)setUpdatesDisabled 309 | { 310 | [[FXBlurScheduler sharedInstance] setUpdatesDisabled]; 311 | } 312 | 313 | + (Class)layerClass 314 | { 315 | return [FXBlurLayer class]; 316 | } 317 | 318 | - (void)setUp 319 | { 320 | if (!_iterationsSet) _iterations = 3; 321 | if (!_blurRadiusSet) [self blurLayer].blurRadius = 40; 322 | if (!_dynamicSet) _dynamic = YES; 323 | if (!_blurEnabledSet) _blurEnabled = YES; 324 | self.updateInterval = _updateInterval; 325 | self.layer.magnificationFilter = @"linear"; // kCAFilterLinear 326 | 327 | unsigned int numberOfMethods; 328 | Method *methods = class_copyMethodList([UIView class], &numberOfMethods); 329 | for (unsigned int i = 0; i < numberOfMethods; i++) 330 | { 331 | Method method = methods[i]; 332 | SEL selector = method_getName(method); 333 | if (selector == @selector(tintColor)) 334 | { 335 | _tintColor = ((id (*)(id,SEL))method_getImplementation(method))(self, selector); 336 | break; 337 | } 338 | } 339 | free(methods); 340 | 341 | } 342 | 343 | - (id)initWithFrame:(CGRect)frame 344 | { 345 | if ((self = [super initWithFrame:frame])) 346 | { 347 | [self setUp]; 348 | self.clipsToBounds = YES; 349 | } 350 | return self; 351 | } 352 | 353 | - (id)initWithCoder:(NSCoder *)aDecoder 354 | { 355 | if ((self = [super initWithCoder:aDecoder])) 356 | { 357 | [self setUp]; 358 | } 359 | return self; 360 | } 361 | 362 | - (void)dealloc 363 | { 364 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 365 | } 366 | 367 | 368 | - (BOOL)viewOrSubviewNeedsDrawViewHierarchy:(UIView *)view 369 | { 370 | if ([view isKindOfClass:NSClassFromString(@"SKView")] || 371 | [view.layer isKindOfClass:NSClassFromString(@"CAEAGLLayer")] || 372 | [view.layer isKindOfClass:NSClassFromString(@"AVPlayerLayer")] || 373 | ABS(view.layer.transform.m34) > 0) 374 | { 375 | return YES; 376 | } 377 | for (UIView *subview in view.subviews) 378 | { 379 | if ([self viewOrSubviewNeedsDrawViewHierarchy:subview]) 380 | { 381 | return YES; 382 | } 383 | } 384 | return NO; 385 | } 386 | 387 | - (void)willMoveToSuperview:(UIView *)newSuperview 388 | { 389 | [super willMoveToSuperview:newSuperview]; 390 | if (!_underlyingView) 391 | { 392 | _needsDrawViewHierarchy = [self viewOrSubviewNeedsDrawViewHierarchy:newSuperview]; 393 | } 394 | } 395 | 396 | - (void)setIterations:(NSUInteger)iterations 397 | { 398 | _iterationsSet = YES; 399 | _iterations = iterations; 400 | [self setNeedsDisplay]; 401 | } 402 | 403 | - (void)setBlurRadius:(CGFloat)blurRadius 404 | { 405 | _blurRadiusSet = YES; 406 | [self blurLayer].blurRadius = blurRadius; 407 | } 408 | 409 | - (CGFloat)blurRadius 410 | { 411 | return [self blurLayer].blurRadius; 412 | } 413 | 414 | - (void)setBlurEnabled:(BOOL)blurEnabled 415 | { 416 | _blurEnabledSet = YES; 417 | if (_blurEnabled != blurEnabled) 418 | { 419 | _blurEnabled = blurEnabled; 420 | [self schedule]; 421 | if (_blurEnabled) 422 | { 423 | [self setNeedsDisplay]; 424 | } 425 | } 426 | } 427 | 428 | - (void)setDynamic:(BOOL)dynamic 429 | { 430 | _dynamicSet = YES; 431 | if (_dynamic != dynamic) 432 | { 433 | _dynamic = dynamic; 434 | [self schedule]; 435 | if (!dynamic) 436 | { 437 | [self setNeedsDisplay]; 438 | } 439 | } 440 | } 441 | 442 | - (UIView *)underlyingView 443 | { 444 | return _underlyingView ?: self.superview; 445 | } 446 | 447 | - (void)setUnderlyingView:(UIView *)underlyingView 448 | { 449 | _underlyingView = underlyingView; 450 | _needsDrawViewHierarchy = [self viewOrSubviewNeedsDrawViewHierarchy:self.underlyingView]; 451 | [self setNeedsDisplay]; 452 | } 453 | 454 | - (CALayer *)underlyingLayer 455 | { 456 | return self.underlyingView.layer; 457 | } 458 | 459 | - (FXBlurLayer *)blurLayer 460 | { 461 | return (FXBlurLayer *)self.layer; 462 | } 463 | 464 | - (FXBlurLayer *)blurPresentationLayer 465 | { 466 | FXBlurLayer *blurLayer = [self blurLayer]; 467 | return (FXBlurLayer *)blurLayer.presentationLayer ?: blurLayer; 468 | } 469 | 470 | - (void)setUpdateInterval:(NSTimeInterval)updateInterval 471 | { 472 | _updateInterval = updateInterval; 473 | if (_updateInterval <= 0) _updateInterval = 1.0/60; 474 | } 475 | 476 | - (void)setTintColor:(UIColor *)tintColor 477 | { 478 | _tintColor = tintColor; 479 | [self setNeedsDisplay]; 480 | } 481 | 482 | - (void)clearImage { 483 | self.layer.contents = nil; 484 | [self setNeedsDisplay]; 485 | } 486 | 487 | - (void)didMoveToSuperview 488 | { 489 | [super didMoveToSuperview]; 490 | [self.layer setNeedsDisplay]; 491 | } 492 | 493 | - (void)didMoveToWindow 494 | { 495 | [super didMoveToWindow]; 496 | [self schedule]; 497 | } 498 | 499 | - (void)schedule 500 | { 501 | if (self.window && self.dynamic && self.blurEnabled) 502 | { 503 | [[FXBlurScheduler sharedInstance] addView:self]; 504 | } 505 | else 506 | { 507 | [[FXBlurScheduler sharedInstance] removeView:self]; 508 | } 509 | } 510 | 511 | - (void)setNeedsDisplay 512 | { 513 | [super setNeedsDisplay]; 514 | [self.layer setNeedsDisplay]; 515 | } 516 | 517 | - (BOOL)shouldUpdate 518 | { 519 | __strong CALayer *underlyingLayer = [self underlyingLayer]; 520 | 521 | return 522 | underlyingLayer && !underlyingLayer.hidden && 523 | self.blurEnabled && [FXBlurScheduler sharedInstance].blurEnabled && 524 | !CGRectIsEmpty([self.layer.presentationLayer ?: self.layer bounds]) && !CGRectIsEmpty(underlyingLayer.bounds); 525 | } 526 | 527 | - (void)displayLayer:(__unused CALayer *)layer 528 | { 529 | [self updateAsynchronously:NO completion:NULL]; 530 | } 531 | 532 | - (id)actionForLayer:(CALayer *)layer forKey:(NSString *)key 533 | { 534 | if ([key isEqualToString:@"blurRadius"]) 535 | { 536 | //animations are enabled 537 | CAAnimation *action = (CAAnimation *)[super actionForLayer:layer forKey:@"backgroundColor"]; 538 | if ((NSNull *)action != [NSNull null]) 539 | { 540 | CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:key]; 541 | animation.fromValue = [layer.presentationLayer valueForKey:key]; 542 | 543 | //CAMediatiming attributes 544 | animation.beginTime = action.beginTime; 545 | animation.duration = action.duration; 546 | animation.speed = action.speed; 547 | animation.timeOffset = action.timeOffset; 548 | animation.repeatCount = action.repeatCount; 549 | animation.repeatDuration = action.repeatDuration; 550 | animation.autoreverses = action.autoreverses; 551 | animation.fillMode = action.fillMode; 552 | 553 | //CAAnimation attributes 554 | animation.timingFunction = action.timingFunction; 555 | animation.delegate = action.delegate; 556 | 557 | return animation; 558 | } 559 | } 560 | return [super actionForLayer:layer forKey:key]; 561 | } 562 | 563 | - (UIImage *)snapshotOfUnderlyingView 564 | { 565 | __strong FXBlurLayer *blurLayer = [self blurPresentationLayer]; 566 | __strong CALayer *underlyingLayer = [self underlyingLayer]; 567 | CGRect bounds = [blurLayer convertRect:blurLayer.bounds toLayer:underlyingLayer]; 568 | 569 | self.lastUpdate = [NSDate date]; 570 | CGFloat scale = 0.5; 571 | if (self.iterations) 572 | { 573 | CGFloat blockSize = 12.0/self.iterations; 574 | scale = blockSize/MAX(blockSize * 2, blurLayer.blurRadius); 575 | scale = 1.0/floor(1.0/scale); 576 | } 577 | CGSize size = bounds.size; 578 | if (self.contentMode == UIViewContentModeScaleToFill || 579 | self.contentMode == UIViewContentModeScaleAspectFill || 580 | self.contentMode == UIViewContentModeScaleAspectFit || 581 | self.contentMode == UIViewContentModeRedraw) 582 | { 583 | //prevents edge artefacts 584 | size.width = floor(size.width * scale) / scale; 585 | size.height = floor(size.height * scale) / scale; 586 | } 587 | else if ([[UIDevice currentDevice].systemVersion floatValue] < 7.0 && [UIScreen mainScreen].scale == 1.0) 588 | { 589 | //prevents pixelation on old devices 590 | scale = 1.0; 591 | } 592 | UIGraphicsBeginImageContextWithOptions(size, NO, scale); 593 | CGContextRef context = UIGraphicsGetCurrentContext(); 594 | if (context) 595 | { 596 | CGContextTranslateCTM(context, -bounds.origin.x, -bounds.origin.y); 597 | 598 | NSArray *hiddenViews = [self prepareUnderlyingViewForSnapshot]; 599 | if (self.needsDrawViewHierarchy) 600 | { 601 | __strong UIView *underlyingView = self.underlyingView; 602 | [underlyingView drawViewHierarchyInRect:underlyingView.bounds afterScreenUpdates:YES]; 603 | } 604 | else 605 | { 606 | [underlyingLayer renderInContext:context]; 607 | } 608 | [self restoreSuperviewAfterSnapshot:hiddenViews]; 609 | UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext(); 610 | UIGraphicsEndImageContext(); 611 | return snapshot; 612 | } 613 | return nil; 614 | } 615 | 616 | - (NSArray *)hideEmptyLayers:(CALayer *)layer 617 | { 618 | NSMutableArray *layers = [NSMutableArray array]; 619 | if (CGRectIsEmpty(layer.bounds)) 620 | { 621 | layer.hidden = YES; 622 | [layers addObject:layer]; 623 | } 624 | for (CALayer *sublayer in layer.sublayers) 625 | { 626 | [layers addObjectsFromArray:[self hideEmptyLayers:sublayer]]; 627 | } 628 | return layers; 629 | } 630 | 631 | - (NSArray *)prepareUnderlyingViewForSnapshot 632 | { 633 | __strong CALayer *blurlayer = [self blurLayer]; 634 | __strong CALayer *underlyingLayer = [self underlyingLayer]; 635 | while (blurlayer.superlayer && blurlayer.superlayer != underlyingLayer) 636 | { 637 | blurlayer = blurlayer.superlayer; 638 | } 639 | NSMutableArray *layers = [NSMutableArray array]; 640 | NSUInteger index = [underlyingLayer.sublayers indexOfObject:blurlayer]; 641 | if (index != NSNotFound) 642 | { 643 | for (NSUInteger i = index; i < [underlyingLayer.sublayers count]; i++) 644 | { 645 | CALayer *layer = underlyingLayer.sublayers[i]; 646 | if (!layer.hidden) 647 | { 648 | layer.hidden = YES; 649 | [layers addObject:layer]; 650 | } 651 | } 652 | } 653 | 654 | //also hide any sublayers with empty bounds to prevent a crash on iOS 8 655 | [layers addObjectsFromArray:[self hideEmptyLayers:underlyingLayer]]; 656 | 657 | return layers; 658 | } 659 | 660 | - (void)restoreSuperviewAfterSnapshot:(NSArray *)hiddenLayers 661 | { 662 | for (CALayer *layer in hiddenLayers) 663 | { 664 | layer.hidden = NO; 665 | } 666 | } 667 | 668 | - (UIImage *)blurredSnapshot:(UIImage *)snapshot radius:(CGFloat)blurRadius 669 | { 670 | return [snapshot blurredImageWithRadius:blurRadius 671 | iterations:self.iterations 672 | tintColor:self.tintColor]; 673 | } 674 | 675 | - (void)setLayerContents:(UIImage *)image 676 | { 677 | self.layer.contents = (id)image.CGImage; 678 | self.layer.contentsScale = image.scale; 679 | } 680 | 681 | - (void)updateAsynchronously:(BOOL)async completion:(void (^)())completion 682 | { 683 | if ([self shouldUpdate]) 684 | { 685 | UIImage *snapshot = [self snapshotOfUnderlyingView]; 686 | if (async) 687 | { 688 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 689 | 690 | UIImage *blurredImage = [self blurredSnapshot:snapshot radius:self.blurRadius]; 691 | dispatch_sync(dispatch_get_main_queue(), ^{ 692 | 693 | [self setLayerContents:blurredImage]; 694 | if (completion) completion(); 695 | }); 696 | }); 697 | } 698 | else 699 | { 700 | [self setLayerContents:[self blurredSnapshot:snapshot radius:[self blurPresentationLayer].blurRadius]]; 701 | if (completion) completion(); 702 | } 703 | } 704 | else if (completion) 705 | { 706 | completion(); 707 | } 708 | } 709 | 710 | @end 711 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/InteractiveTransition.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogInteractiveTransition.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | // Handles interactive transition triggered via pan gesture recognizer on dialog 29 | final internal class InteractiveTransition: UIPercentDrivenInteractiveTransition { 30 | 31 | // If the interactive transition was started 32 | var hasStarted = false 33 | 34 | // If the interactive transition 35 | var shouldFinish = false 36 | 37 | // The view controller containing the views 38 | // with attached gesture recognizers 39 | weak var viewController: UIViewController? = nil 40 | 41 | @objc func handlePan(_ sender: UIPanGestureRecognizer) { 42 | 43 | guard let vc = viewController else { return } 44 | 45 | guard let progress = calculateProgress(sender: sender) else { return } 46 | 47 | switch sender.state { 48 | case .began: 49 | hasStarted = true 50 | vc.dismiss(animated: true, completion: nil) 51 | case .changed: 52 | shouldFinish = progress > 0.3 53 | update(progress) 54 | case .cancelled: 55 | hasStarted = false 56 | cancel() 57 | case .ended: 58 | hasStarted = false 59 | completionSpeed = 0.55 60 | shouldFinish ? finish() : cancel() 61 | default: 62 | break 63 | } 64 | } 65 | } 66 | 67 | internal extension InteractiveTransition { 68 | 69 | /*! 70 | Translates the pan gesture recognizer position to the progress percentage 71 | - parameter sender: A UIPanGestureRecognizer 72 | - returns: Progress 73 | */ 74 | func calculateProgress(sender: UIPanGestureRecognizer) -> CGFloat? { 75 | guard let vc = viewController else { return nil } 76 | 77 | // http://www.thorntech.com/2016/02/ios-tutorial-close-modal-dragging/ 78 | let translation = sender.translation(in: vc.view) 79 | let verticalMovement = translation.y / vc.view.bounds.height 80 | let downwardMovement = fmaxf(Float(verticalMovement), 0.0) 81 | let downwardMovementPercent = fminf(downwardMovement, 1.0) 82 | let progress = CGFloat(downwardMovementPercent) 83 | 84 | return progress 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialog+Keyboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialog+Keyboard.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /// This extension is designed to handle dialog positioning 30 | /// if a keyboard is displayed while the popup is on top 31 | internal extension PopupDialog { 32 | 33 | // MARK: - Keyboard & orientation observers 34 | 35 | /*! Add obserservers for UIKeyboard notifications */ 36 | internal func addObservers() { 37 | NotificationCenter.default.addObserver(self, selector: #selector(orientationChanged), 38 | name: NSNotification.Name.UIDeviceOrientationDidChange, 39 | object: nil) 40 | 41 | NotificationCenter.default.addObserver(self, 42 | selector: #selector(keyboardWillShow), 43 | name: NSNotification.Name.UIKeyboardWillShow, 44 | object: nil) 45 | 46 | NotificationCenter.default.addObserver(self, 47 | selector: #selector(keyboardWillHide), 48 | name: NSNotification.Name.UIKeyboardWillHide, 49 | object: nil) 50 | 51 | NotificationCenter.default.addObserver(self, 52 | selector: #selector(keyboardWillChangeFrame), 53 | name: NSNotification.Name.UIKeyboardWillChangeFrame, 54 | object: nil) 55 | } 56 | 57 | /*! Remove observers */ 58 | internal func removeObservers() { 59 | NotificationCenter.default.removeObserver(self, 60 | name: NSNotification.Name.UIDeviceOrientationDidChange, 61 | object: nil) 62 | 63 | NotificationCenter.default.removeObserver(self, 64 | name: NSNotification.Name.UIKeyboardWillShow, 65 | object: nil) 66 | 67 | NotificationCenter.default.removeObserver(self, 68 | name: NSNotification.Name.UIKeyboardWillHide, 69 | object: nil) 70 | 71 | NotificationCenter.default.removeObserver(self, 72 | name: NSNotification.Name.UIKeyboardWillChangeFrame, 73 | object: nil) 74 | } 75 | 76 | // MARK: - Actions 77 | 78 | /*! 79 | Keyboard will show notification listener 80 | - parameter notification: NSNotification 81 | */ 82 | @objc fileprivate func keyboardWillShow(_ notification: Notification) { 83 | guard isTopAndVisible else { return } 84 | keyboardShown = true 85 | centerPopup() 86 | } 87 | 88 | /*! 89 | Keyboard will hide notification listener 90 | - parameter notification: NSNotification 91 | */ 92 | @objc fileprivate func keyboardWillHide(_ notification: Notification) { 93 | guard isTopAndVisible else { return } 94 | keyboardShown = false 95 | centerPopup() 96 | } 97 | 98 | /*! 99 | Keyboard will change frame notification listener 100 | - parameter notification: NSNotification 101 | */ 102 | @objc fileprivate func keyboardWillChangeFrame(_ notification: Notification) { 103 | guard let keyboardRect = (notification as NSNotification).userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue else { 104 | return 105 | } 106 | keyboardHeight = keyboardRect.cgRectValue.height 107 | } 108 | 109 | /*! 110 | Listen to orientation changes 111 | - parameter notification: NSNotification 112 | */ 113 | @objc fileprivate func orientationChanged(_ notification: Notification) { 114 | if keyboardShown { centerPopup() } 115 | } 116 | 117 | fileprivate func centerPopup() { 118 | 119 | // Make sure keyboard should reposition on keayboard notifications 120 | guard keyboardShiftsView else { return } 121 | 122 | // Make sure a valid keyboard height is available 123 | guard let keyboardHeight = keyboardHeight else { return } 124 | 125 | // Calculate new center of shadow background 126 | let popupCenter = keyboardShown ? keyboardHeight / -2 : 0 127 | 128 | // Reposition and animate 129 | popupContainerView.centerYConstraint?.constant = popupCenter 130 | popupContainerView.pv_layoutIfNeededAnimated() 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialog.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /// Creates a Popup dialog similar to UIAlertController 30 | final public class PopupDialog: UIViewController { 31 | 32 | // MARK: Private / Internal 33 | 34 | /// First init flag 35 | fileprivate var initialized = false 36 | 37 | /// The completion handler 38 | fileprivate var completion: (() -> Void)? = nil 39 | 40 | /// The custom transition presentation manager 41 | fileprivate var presentationManager: PresentationManager! 42 | 43 | /// Interactor class for pan gesture dismissal 44 | fileprivate lazy var interactor = InteractiveTransition() 45 | 46 | /// Returns the controllers view 47 | internal var popupContainerView: PopupDialogContainerView { 48 | return view as! PopupDialogContainerView 49 | } 50 | 51 | /// The set of buttons 52 | fileprivate var buttons = [PopupDialogButton]() 53 | 54 | /// Whether keyboard has shifted view 55 | internal var keyboardShown = false 56 | 57 | /// Keyboard height 58 | internal var keyboardHeight: CGFloat? = nil 59 | 60 | // MARK: Public 61 | 62 | /// The content view of the popup dialog 63 | public var viewController: UIViewController 64 | 65 | /// Whether or not to shift view for keyboard display 66 | public var keyboardShiftsView = true 67 | 68 | // MARK: - Initializers 69 | 70 | /*! 71 | Creates a standard popup dialog with title, message and image field 72 | 73 | - parameter title: The dialog title 74 | - parameter message: The dialog message 75 | - parameter image: The dialog image 76 | - parameter buttonAlignment: The dialog button alignment 77 | - parameter transitionStyle: The dialog transition style 78 | - parameter gestureDismissal: Indicates if dialog can be dismissed via pan gesture 79 | - parameter completion: Completion block invoked when dialog was dismissed 80 | 81 | - returns: Popup dialog default style 82 | */ 83 | public convenience init( 84 | title: String?, 85 | message: String?, 86 | image: UIImage? = nil, 87 | buttonAlignment: UILayoutConstraintAxis = .vertical, 88 | transitionStyle: PopupDialogTransitionStyle = .bounceUp, 89 | gestureDismissal: Bool = true, 90 | completion: (() -> Void)? = nil) { 91 | 92 | // Create and configure the standard popup dialog view 93 | let viewController = PopupDialogDefaultViewController() 94 | viewController.titleText = title 95 | viewController.messageText = message 96 | viewController.image = image 97 | 98 | // Call designated initializer 99 | self.init(viewController: viewController, buttonAlignment: buttonAlignment, transitionStyle: transitionStyle, gestureDismissal: gestureDismissal, completion: completion) 100 | } 101 | 102 | /*! 103 | Creates a popup dialog containing a custom view 104 | 105 | - parameter viewController: A custom view controller to be displayed 106 | - parameter buttonAlignment: The dialog button alignment 107 | - parameter transitionStyle: The dialog transition style 108 | - parameter gestureDismissal: Indicates if dialog can be dismissed via pan gesture 109 | - parameter completion: Completion block invoked when dialog was dismissed 110 | 111 | - returns: Popup dialog with a custom view controller 112 | */ 113 | public init( 114 | viewController: UIViewController, 115 | buttonAlignment: UILayoutConstraintAxis = .vertical, 116 | transitionStyle: PopupDialogTransitionStyle = .bounceUp, 117 | gestureDismissal: Bool = true, 118 | completion: (() -> Void)? = nil) { 119 | 120 | self.viewController = viewController 121 | self.completion = completion 122 | super.init(nibName: nil, bundle: nil) 123 | 124 | // Init the presentation manager 125 | presentationManager = PresentationManager(transitionStyle: transitionStyle, interactor: interactor) 126 | 127 | // Assign the interactor view controller 128 | interactor.viewController = self 129 | 130 | // Define presentation styles 131 | transitioningDelegate = presentationManager 132 | modalPresentationStyle = .custom 133 | 134 | // Add our custom view to the container 135 | if #available(iOS 9.0, *) { 136 | if let stackView = popupContainerView.stackView as? UIStackView { 137 | stackView.insertArrangedSubview(viewController.view, at: 0) 138 | } 139 | } else { 140 | if let stackView = popupContainerView.stackView as? TZStackView { 141 | stackView.insertArrangedSubview(viewController.view, at: 0) 142 | } 143 | } 144 | 145 | // Set button alignment 146 | if #available(iOS 9.0, *) { 147 | if let stackView = popupContainerView.buttonStackView as? UIStackView { 148 | stackView.axis = buttonAlignment 149 | } 150 | } else { 151 | if let stackView = popupContainerView.buttonStackView as? TZStackView { 152 | stackView.axis = buttonAlignment 153 | } 154 | } 155 | 156 | // Allow for dialog dismissal on background tap and dialog pan gesture 157 | if gestureDismissal { 158 | let panRecognizer = UIPanGestureRecognizer(target: interactor, action: #selector(InteractiveTransition.handlePan)) 159 | popupContainerView.stackView.addGestureRecognizer(panRecognizer) 160 | let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) 161 | popupContainerView.addGestureRecognizer(tapRecognizer) 162 | } 163 | } 164 | 165 | // Init with coder not implemented 166 | required public init?(coder aDecoder: NSCoder) { 167 | fatalError("init(coder:) has not been implemented") 168 | } 169 | 170 | // MARK: - View life cycle 171 | 172 | /// Replaces controller view with popup view 173 | public override func loadView() { 174 | view = PopupDialogContainerView(frame: UIScreen.main.bounds) 175 | } 176 | 177 | public override func viewWillAppear(_ animated: Bool) { 178 | super.viewWillAppear(animated) 179 | 180 | guard !initialized else { return } 181 | appendButtons() 182 | addObservers() 183 | initialized = true 184 | } 185 | 186 | public override func viewWillDisappear(_ animated: Bool) { 187 | super.viewWillDisappear(animated) 188 | removeObservers() 189 | } 190 | 191 | deinit { 192 | completion?() 193 | completion = nil 194 | } 195 | 196 | // MARK - Dismissal related 197 | 198 | @objc fileprivate func handleTap(_ sender: UITapGestureRecognizer) { 199 | 200 | // Make sure it's not a tap on the dialog but the background 201 | let point = sender.location(in: popupContainerView.stackView) 202 | guard !popupContainerView.stackView.point(inside: point, with: nil) else { return } 203 | dismiss() 204 | } 205 | 206 | /*! 207 | Dismisses the popup dialog 208 | */ 209 | public func dismiss(_ completion: (() -> Void)? = nil) { 210 | self.dismiss(animated: true) { 211 | completion?() 212 | } 213 | } 214 | 215 | // MARK: - Button related 216 | 217 | /*! 218 | Appends the buttons added to the popup dialog 219 | to the placeholder stack view 220 | */ 221 | fileprivate func appendButtons() { 222 | // Add action to buttons 223 | if #available(iOS 9.0, *) { 224 | let stackView = popupContainerView.stackView as! UIStackView 225 | let buttonStackView = popupContainerView.buttonStackView as! UIStackView 226 | if buttons.isEmpty { 227 | stackView.removeArrangedSubview(popupContainerView.buttonStackView) 228 | } 229 | 230 | for (index, button) in buttons.enumerated() { 231 | button.needsLeftSeparator = buttonStackView.axis == .horizontal && index > 0 232 | buttonStackView.addArrangedSubview(button) 233 | button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) 234 | } 235 | } else { 236 | let stackView = popupContainerView.stackView as! TZStackView 237 | let buttonStackView = popupContainerView.buttonStackView as! TZStackView 238 | if buttons.isEmpty { 239 | stackView.removeArrangedSubview(popupContainerView.buttonStackView) 240 | } 241 | 242 | for (index, button) in buttons.enumerated() { 243 | button.needsLeftSeparator = buttonStackView.axis == .horizontal && index > 0 244 | buttonStackView.addArrangedSubview(button) 245 | button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside) 246 | } 247 | } 248 | } 249 | 250 | /*! 251 | Adds a single PopupDialogButton to the Popup dialog 252 | - parameter button: A PopupDialogButton instance 253 | */ 254 | public func addButton(_ button: PopupDialogButton) { 255 | buttons.append(button) 256 | } 257 | 258 | /*! 259 | Adds an array of PopupDialogButtons to the Popup dialog 260 | - parameter buttons: A list of PopupDialogButton instances 261 | */ 262 | public func addButtons(_ buttons: [PopupDialogButton]) { 263 | self.buttons += buttons 264 | } 265 | 266 | /// Calls the action closure of the button instance tapped 267 | @objc fileprivate func buttonTapped(_ button: PopupDialogButton) { 268 | if button.dismissOnTap { 269 | dismiss() { button.buttonAction?() } 270 | } else { 271 | button.buttonAction?() 272 | } 273 | } 274 | 275 | /*! 276 | Simulates a button tap for the given index 277 | Makes testing a breeze 278 | - parameter index: The index of the button to tap 279 | */ 280 | public func tapButtonWithIndex(_ index: Int) { 281 | let button = buttons[index] 282 | button.buttonAction?() 283 | } 284 | } 285 | 286 | // MARK: - View proxy values 287 | 288 | extension PopupDialog { 289 | 290 | /// The button alignment of the alert dialog 291 | public var buttonAlignment: UILayoutConstraintAxis { 292 | get { 293 | if #available(iOS 9.0, *) { 294 | let buttonStackView = popupContainerView.buttonStackView as! UIStackView 295 | return buttonStackView.axis 296 | } else { 297 | let buttonStackView = popupContainerView.buttonStackView as! TZStackView 298 | return buttonStackView.axis 299 | } 300 | } 301 | set { 302 | if #available(iOS 9.0, *) { 303 | let buttonStackView = popupContainerView.buttonStackView as! UIStackView 304 | buttonStackView.axis = newValue 305 | 306 | } else { 307 | let buttonStackView = popupContainerView.buttonStackView as! TZStackView 308 | buttonStackView.axis = newValue 309 | } 310 | popupContainerView.pv_layoutIfNeededAnimated() 311 | } 312 | } 313 | 314 | /// The transition style 315 | public var transitionStyle: PopupDialogTransitionStyle { 316 | get { return presentationManager.transitionStyle } 317 | set { presentationManager.transitionStyle = newValue } 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogButton.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /// Represents the default button for the popup dialog 30 | open class PopupDialogButton: UIButton { 31 | 32 | public typealias PopupDialogButtonAction = () -> Void 33 | 34 | // MARK: Public 35 | 36 | /// The font and size of the button title 37 | open dynamic var titleFont: UIFont? { 38 | get { return titleLabel?.font } 39 | set { titleLabel?.font = newValue } 40 | } 41 | 42 | /// The height of the button 43 | open dynamic var buttonHeight: Int 44 | 45 | /// The title color of the button 46 | open dynamic var titleColor: UIColor? { 47 | get { return self.titleColor(for: UIControlState()) } 48 | set { setTitleColor(newValue, for: UIControlState()) } 49 | } 50 | 51 | /// The background color of the button 52 | open dynamic var buttonColor: UIColor? { 53 | get { return backgroundColor } 54 | set { backgroundColor = newValue } 55 | } 56 | 57 | /// The separator color of this button 58 | open dynamic var separatorColor: UIColor? { 59 | get { return separator.backgroundColor } 60 | set { 61 | separator.backgroundColor = newValue 62 | leftSeparator.backgroundColor = newValue 63 | } 64 | } 65 | 66 | /// Default appearance of the button 67 | open var defaultTitleFont = UIFont.systemFont(ofSize: 14) 68 | open var defaultTitleColor = UIColor(red: 0.25, green: 0.53, blue: 0.91, alpha: 1) 69 | open var defaultButtonColor = UIColor.clear 70 | open var defaultSeparatorColor = UIColor(white: 0.9, alpha: 1) 71 | 72 | /// Whether button should dismiss popup when tapped 73 | open var dismissOnTap = true 74 | 75 | /// The action called when the button is tapped 76 | open fileprivate(set) var buttonAction: PopupDialogButtonAction? 77 | 78 | // MARK: Private 79 | 80 | fileprivate lazy var separator: UIView = { 81 | let line = UIView(frame: .zero) 82 | line.translatesAutoresizingMaskIntoConstraints = false 83 | return line 84 | }() 85 | 86 | fileprivate lazy var leftSeparator: UIView = { 87 | let line = UIView(frame: .zero) 88 | line.translatesAutoresizingMaskIntoConstraints = false 89 | line.alpha = 0 90 | return line 91 | }() 92 | 93 | // MARK: Internal 94 | 95 | internal var needsLeftSeparator: Bool = false { 96 | didSet { 97 | leftSeparator.alpha = needsLeftSeparator ? 1.0 : 0.0 98 | } 99 | } 100 | 101 | // MARK: Initializers 102 | 103 | /*! 104 | Creates a button that can be added to the popup dialog 105 | 106 | - parameter title: The button title 107 | - parameter dismisssOnTap: Whether a tap automatically dismisses the dialog 108 | - parameter action: The action closure 109 | 110 | - returns: PopupDialogButton 111 | */ 112 | public init(title: String, 113 | height: Int = 45, 114 | dismissOnTap: Bool = true, action: PopupDialogButtonAction?) { 115 | 116 | // Assign the button height 117 | buttonHeight = height 118 | 119 | // Assign the button action 120 | buttonAction = action 121 | 122 | super.init(frame: .zero) 123 | 124 | // Set the button title 125 | setTitle(title, for: UIControlState()) 126 | 127 | self.dismissOnTap = dismissOnTap 128 | 129 | // Setup the views 130 | setupView() 131 | } 132 | 133 | required public init?(coder aDecoder: NSCoder) { 134 | fatalError("init(coder:) has not been implemented") 135 | } 136 | 137 | // MARK: View setup 138 | 139 | open func setupView() { 140 | 141 | // Default appearance 142 | setTitleColor(defaultTitleColor, for: UIControlState()) 143 | titleLabel?.font = defaultTitleFont 144 | backgroundColor = defaultButtonColor 145 | separator.backgroundColor = defaultSeparatorColor 146 | leftSeparator.backgroundColor = defaultSeparatorColor 147 | 148 | // Add and layout views 149 | addSubview(separator) 150 | addSubview(leftSeparator) 151 | 152 | let views = ["separator": separator, "leftSeparator": leftSeparator, "button": self] 153 | let metrics = ["buttonHeight": buttonHeight] 154 | var constraints = [NSLayoutConstraint]() 155 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:[button(buttonHeight)]", options: [], metrics: metrics, views: views) 156 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[separator]|", options: [], metrics: nil, views: views) 157 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[separator(1)]", options: [], metrics: nil, views: views) 158 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[leftSeparator(1)]", options: [], metrics: nil, views: views) 159 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[leftSeparator]|", options: [], metrics: nil, views: views) 160 | NSLayoutConstraint.activate(constraints) 161 | } 162 | 163 | open override var isHighlighted: Bool { 164 | didSet { 165 | isHighlighted ? pv_fade(.out, 0.5) : pv_fade(.in, 1.0) 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogContainerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogContainerView.swift 3 | // Pods 4 | // 5 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 6 | // Author - Martin Wildfeuer (http://www.mwfire.de) 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | // 26 | 27 | import Foundation 28 | import UIKit 29 | 30 | /// The main view of the popup dialog 31 | final public class PopupDialogContainerView: UIView { 32 | 33 | // MARK: - Appearance 34 | 35 | /// The background color of the popup dialog 36 | override public dynamic var backgroundColor: UIColor? { 37 | get { return container.backgroundColor } 38 | set { container.backgroundColor = newValue } 39 | } 40 | 41 | /// The corner radius of the popup view 42 | public dynamic var cornerRadius: Float { 43 | get { return Float(shadowContainer.layer.cornerRadius) } 44 | set { 45 | let radius = CGFloat(newValue) 46 | shadowContainer.layer.cornerRadius = radius 47 | container.layer.cornerRadius = radius 48 | } 49 | } 50 | 51 | /// Enable / disable shadow rendering 52 | public dynamic var shadowEnabled: Bool { 53 | get { return shadowContainer.layer.shadowRadius > 0 } 54 | set { shadowContainer.layer.shadowRadius = newValue ? 5 : 0 } 55 | } 56 | 57 | /// The shadow color 58 | public dynamic var shadowColor: UIColor? { 59 | get { 60 | guard let color = shadowContainer.layer.shadowColor else { 61 | return nil 62 | } 63 | return UIColor(cgColor: color) 64 | } 65 | set { shadowContainer.layer.shadowColor = newValue?.cgColor } 66 | } 67 | 68 | // MARK: - Views 69 | 70 | /// The shadow container is the basic view of the PopupDialog 71 | /// As it does not clip subviews, a shadow can be applied to it 72 | internal lazy var shadowContainer: UIView = { 73 | let shadowContainer = UIView(frame: .zero) 74 | shadowContainer.translatesAutoresizingMaskIntoConstraints = false 75 | shadowContainer.backgroundColor = UIColor.clear 76 | shadowContainer.layer.shadowColor = UIColor.black.cgColor 77 | shadowContainer.layer.shadowRadius = 5 78 | shadowContainer.layer.shadowOpacity = 0.4 79 | shadowContainer.layer.shadowOffset = CGSize(width: 0, height: 0) 80 | shadowContainer.layer.cornerRadius = 4 81 | return shadowContainer 82 | }() 83 | 84 | /// The container view is a child of shadowContainer and contains 85 | /// all other views. It clips to bounds so cornerRadius can be set 86 | internal lazy var container: UIView = { 87 | let container = UIView(frame: .zero) 88 | container.translatesAutoresizingMaskIntoConstraints = false 89 | container.backgroundColor = UIColor.white 90 | container.clipsToBounds = true 91 | container.layer.cornerRadius = 4 92 | return container 93 | }() 94 | 95 | // The container stack view for buttons 96 | internal lazy var buttonStackView: UIView = { 97 | if #available(iOS 9.0, *) { 98 | let buttonStackView = UIStackView() 99 | buttonStackView.translatesAutoresizingMaskIntoConstraints = false 100 | buttonStackView.distribution = .fillEqually 101 | buttonStackView.spacing = 0 102 | return buttonStackView 103 | } else { 104 | let buttonStackView = TZStackView() 105 | buttonStackView.translatesAutoresizingMaskIntoConstraints = false 106 | buttonStackView.distribution = .fillEqually 107 | buttonStackView.spacing = 0 108 | return buttonStackView 109 | } 110 | }() 111 | 112 | // The main stack view, containing all relevant views 113 | internal lazy var stackView: UIView = { 114 | if #available(iOS 9.0, *) { 115 | let stackView = UIStackView(arrangedSubviews: [self.buttonStackView]) 116 | stackView.translatesAutoresizingMaskIntoConstraints = false 117 | stackView.axis = .vertical 118 | stackView.spacing = 0 119 | return stackView 120 | } else { 121 | let stackView = TZStackView(arrangedSubviews: [self.buttonStackView]) 122 | stackView.translatesAutoresizingMaskIntoConstraints = false 123 | stackView.axis = .vertical 124 | stackView.spacing = 0 125 | return stackView 126 | } 127 | }() 128 | 129 | // MARK: - Constraints 130 | 131 | /// The center constraint of the shadow container 132 | internal var centerYConstraint: NSLayoutConstraint? = nil 133 | 134 | // MARK: - Initializers 135 | 136 | internal override init(frame: CGRect) { 137 | super.init(frame: frame) 138 | setupViews() 139 | } 140 | 141 | required public init?(coder aDecoder: NSCoder) { 142 | fatalError("init(coder:) has not been implemented") 143 | } 144 | 145 | // MARK: - View setup 146 | 147 | internal func setupViews() { 148 | 149 | // Add views 150 | addSubview(shadowContainer) 151 | shadowContainer.addSubview(container) 152 | container.addSubview(stackView) 153 | 154 | // Layout views 155 | let views = ["shadowContainer": shadowContainer, "container": container, "stackView": stackView] 156 | var constraints = [NSLayoutConstraint]() 157 | 158 | // Shadow container constraints 159 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|-(>=10,==20@900)-[shadowContainer(<=340,>=300)]-(>=10,==20@900)-|", options: [], metrics: nil, views: views) 160 | constraints += [NSLayoutConstraint(item: shadowContainer, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .centerX, multiplier: 1, constant: 0)] 161 | centerYConstraint = NSLayoutConstraint(item: shadowContainer, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1, constant: 0) 162 | constraints.append(centerYConstraint!) 163 | 164 | // Container constraints 165 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[container]|", options: [], metrics: nil, views: views) 166 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[container]|", options: [], metrics: nil, views: views) 167 | 168 | // Main stack view constraints 169 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[stackView]|", options: [], metrics: nil, views: views) 170 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[stackView]|", options: [], metrics: nil, views: views) 171 | 172 | // Activate constraints 173 | NSLayoutConstraint.activate(constraints) 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogDefaultButtons.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogDefaultButtons.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | // MARK: Default button 30 | 31 | /// Represents the default button for the popup dialog 32 | public final class DefaultButton: PopupDialogButton {} 33 | 34 | // MARK: Cancel button 35 | 36 | /// Represents a cancel button for the popup dialog 37 | public final class CancelButton: PopupDialogButton { 38 | 39 | override public func setupView() { 40 | defaultTitleColor = UIColor.lightGray 41 | super.setupView() 42 | } 43 | } 44 | 45 | // MARK: destructive button 46 | 47 | /// Represents a destructive button for the popup dialog 48 | public final class DestructiveButton: PopupDialogButton { 49 | 50 | override public func setupView() { 51 | defaultTitleColor = UIColor.red 52 | super.setupView() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogDefaultView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogView.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /// The main view of the popup dialog 30 | final public class PopupDialogDefaultView: UIView { 31 | 32 | // MARK: - Appearance 33 | 34 | /// The font and size of the title label 35 | public dynamic var titleFont: UIFont { 36 | get { return titleLabel.font } 37 | set { titleLabel.font = newValue } 38 | } 39 | 40 | /// The color of the title label 41 | public dynamic var titleColor: UIColor? { 42 | get { return titleLabel.textColor } 43 | set { titleLabel.textColor = newValue } 44 | } 45 | 46 | /// The text alignment of the title label 47 | public dynamic var titleTextAlignment: NSTextAlignment { 48 | get { return titleLabel.textAlignment } 49 | set { titleLabel.textAlignment = newValue } 50 | } 51 | 52 | /// The font and size of the body label 53 | public dynamic var messageFont: UIFont { 54 | get { return messageLabel.font } 55 | set { messageLabel.font = newValue } 56 | } 57 | 58 | /// The color of the message label 59 | public dynamic var messageColor: UIColor? { 60 | get { return messageLabel.textColor } 61 | set { messageLabel.textColor = newValue} 62 | } 63 | 64 | /// The text alignment of the message label 65 | public dynamic var messageTextAlignment: NSTextAlignment { 66 | get { return messageLabel.textAlignment } 67 | set { messageLabel.textAlignment = newValue } 68 | } 69 | 70 | // MARK: - Views 71 | 72 | /// The view that will contain the image, if set 73 | internal lazy var imageView: UIImageView = { 74 | let imageView = UIImageView(frame: .zero) 75 | imageView.translatesAutoresizingMaskIntoConstraints = false 76 | imageView.contentMode = .scaleAspectFit 77 | imageView.clipsToBounds = true 78 | return imageView 79 | }() 80 | 81 | /// The title label of the dialog 82 | internal lazy var titleLabel: UILabel = { 83 | let titleLabel = UILabel(frame: .zero) 84 | titleLabel.translatesAutoresizingMaskIntoConstraints = false 85 | titleLabel.numberOfLines = 0 86 | titleLabel.textAlignment = .center 87 | titleLabel.textColor = UIColor(white: 0.4, alpha: 1) 88 | titleLabel.font = UIFont.boldSystemFont(ofSize: 14) 89 | return titleLabel 90 | }() 91 | 92 | /// The message label of the dialog 93 | internal lazy var messageLabel: UILabel = { 94 | let messageLabel = UILabel(frame: .zero) 95 | messageLabel.translatesAutoresizingMaskIntoConstraints = false 96 | messageLabel.numberOfLines = 0 97 | messageLabel.textAlignment = .center 98 | messageLabel.textColor = UIColor(white: 0.6, alpha: 1) 99 | messageLabel.font = UIFont.systemFont(ofSize: 14) 100 | return messageLabel 101 | }() 102 | 103 | /// The height constraint of the image view, 0 by default 104 | internal var imageHeightConstraint: NSLayoutConstraint? 105 | 106 | // MARK: - Initializers 107 | 108 | internal override init(frame: CGRect) { 109 | super.init(frame: frame) 110 | setupViews() 111 | } 112 | 113 | required public init?(coder aDecoder: NSCoder) { 114 | fatalError("init(coder:) has not been implemented") 115 | } 116 | 117 | // MARK: - View setup 118 | 119 | internal func setupViews() { 120 | 121 | // Self setup 122 | translatesAutoresizingMaskIntoConstraints = false 123 | 124 | // Add views 125 | addSubview(imageView) 126 | addSubview(titleLabel) 127 | addSubview(messageLabel) 128 | 129 | // Layout views 130 | let views = ["imageView": imageView, "titleLabel": titleLabel, "messageLabel": messageLabel] as [String : Any] 131 | var constraints = [NSLayoutConstraint]() 132 | 133 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[imageView]|", options: [], metrics: nil, views: views) 134 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|-(==20@900)-[titleLabel]-(==20@900)-|", options: [], metrics: nil, views: views) 135 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|-(==20@900)-[messageLabel]-(==20@900)-|", options: [], metrics: nil, views: views) 136 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[imageView]-(==30@900)-[titleLabel]-(==8@900)-[messageLabel]-(==30@900)-|", options: [], metrics: nil, views: views) 137 | 138 | // ImageView height constraint 139 | imageHeightConstraint = NSLayoutConstraint(item: imageView, attribute: .height, relatedBy: .equal, toItem: imageView, attribute: .height, multiplier: 0, constant: 0) 140 | constraints.append(imageHeightConstraint!) 141 | 142 | // Activate constraints 143 | NSLayoutConstraint.activate(constraints) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogDefaultViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogDefaultViewController.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import UIKit 27 | 28 | final public class PopupDialogDefaultViewController: UIViewController { 29 | 30 | public var standardView: PopupDialogDefaultView { 31 | return view as! PopupDialogDefaultView 32 | } 33 | 34 | override public func loadView() { 35 | super.loadView() 36 | view = PopupDialogDefaultView(frame: .zero) 37 | } 38 | } 39 | 40 | public extension PopupDialogDefaultViewController { 41 | 42 | // MARK: - Setter / Getter 43 | 44 | // MARK: Content 45 | 46 | /// The dialog image 47 | public var image: UIImage? { 48 | get { return standardView.imageView.image } 49 | set { 50 | standardView.imageView.image = newValue 51 | standardView.imageHeightConstraint?.constant = standardView.imageView.pv_heightForImageView() 52 | } 53 | } 54 | 55 | /// The title text of the dialog 56 | public var titleText: String? { 57 | get { return standardView.titleLabel.text } 58 | set { 59 | standardView.titleLabel.text = newValue 60 | standardView.pv_layoutIfNeededAnimated() 61 | } 62 | } 63 | 64 | /// The message text of the dialog 65 | public var messageText: String? { 66 | get { return standardView.messageLabel.text } 67 | set { 68 | standardView.messageLabel.text = newValue 69 | standardView.pv_layoutIfNeededAnimated() 70 | } 71 | } 72 | 73 | // MARK: Appearance 74 | 75 | /// The font and size of the title label 76 | public dynamic var titleFont: UIFont { 77 | get { return standardView.titleFont } 78 | set { 79 | standardView.titleFont = newValue 80 | standardView.pv_layoutIfNeededAnimated() 81 | } 82 | } 83 | 84 | /// The color of the title label 85 | public dynamic var titleColor: UIColor? { 86 | get { return standardView.titleLabel.textColor } 87 | set { 88 | standardView.titleColor = newValue 89 | standardView.pv_layoutIfNeededAnimated() 90 | } 91 | } 92 | 93 | /// The text alignment of the title label 94 | public dynamic var titleTextAlignment: NSTextAlignment { 95 | get { return standardView.titleTextAlignment } 96 | set { 97 | standardView.titleTextAlignment = newValue 98 | standardView.pv_layoutIfNeededAnimated() 99 | } 100 | } 101 | 102 | /// The font and size of the body label 103 | public dynamic var messageFont: UIFont { 104 | get { return standardView.messageFont} 105 | set { 106 | standardView.messageFont = newValue 107 | standardView.pv_layoutIfNeededAnimated() 108 | } 109 | } 110 | 111 | /// The color of the message label 112 | public dynamic var messageColor: UIColor? { 113 | get { return standardView.messageColor } 114 | set { 115 | standardView.messageColor = newValue 116 | standardView.pv_layoutIfNeededAnimated() 117 | } 118 | } 119 | 120 | /// The text alignment of the message label 121 | public dynamic var messageTextAlignment: NSTextAlignment { 122 | get { return standardView.messageTextAlignment } 123 | set { 124 | standardView.messageTextAlignment = newValue 125 | standardView.pv_layoutIfNeededAnimated() 126 | } 127 | } 128 | 129 | public override func viewDidLayoutSubviews() { 130 | super.viewDidLayoutSubviews() 131 | standardView.imageHeightConstraint?.constant = standardView.imageView.pv_heightForImageView() 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PopupDialogOverlayView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogOverlayView.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | 28 | /// The (blurred) overlay view below the popup dialog 29 | final public class PopupDialogOverlayView: UIView { 30 | 31 | // MARK: - Appearance 32 | 33 | /// The blur radius of the overlay view 34 | public dynamic var blurRadius: Float { 35 | get { return Float(blurView.blurRadius) } 36 | set { blurView.blurRadius = CGFloat(newValue) } 37 | } 38 | 39 | /// Turns the blur of the overlay view on or off 40 | public dynamic var blurEnabled: Bool { 41 | get { return blurView.isBlurEnabled } 42 | set { 43 | blurView.isBlurEnabled = newValue 44 | blurView.alpha = newValue ? 1 : 0 45 | } 46 | } 47 | 48 | /// Whether the blur view should allow for 49 | /// dynamic rendering of the background 50 | public dynamic var liveBlur: Bool { 51 | get { return blurView.isDynamic } 52 | set { return blurView.isDynamic = newValue } 53 | } 54 | 55 | /// The background color of the overlay view 56 | public dynamic var color: UIColor? { 57 | get { return overlay.backgroundColor } 58 | set { overlay.backgroundColor = newValue } 59 | } 60 | 61 | /// The opacity of the overay view 62 | public dynamic var opacity: Float { 63 | get { return Float(overlay.alpha) } 64 | set { overlay.alpha = CGFloat(newValue) } 65 | } 66 | 67 | // MARK: - Views 68 | 69 | internal lazy var blurView: FXBlurView = { 70 | let blurView = FXBlurView(frame: .zero) 71 | blurView.blurRadius = 8 72 | blurView.isDynamic = false 73 | blurView.tintColor = UIColor.clear 74 | blurView.autoresizingMask = [.flexibleHeight, .flexibleWidth] 75 | return blurView 76 | }() 77 | 78 | internal lazy var overlay: UIView = { 79 | let overlay = UIView(frame: .zero) 80 | overlay.backgroundColor = UIColor.black 81 | overlay.autoresizingMask = [.flexibleHeight, .flexibleWidth] 82 | overlay.alpha = 0.7 83 | return overlay 84 | }() 85 | 86 | // MARK: - Inititalizers 87 | 88 | override init(frame: CGRect) { 89 | super.init(frame: frame) 90 | setupView() 91 | } 92 | 93 | required public init?(coder aDecoder: NSCoder) { 94 | fatalError("init(coder:) has not been implemented") 95 | } 96 | 97 | // MARK: - View setup 98 | 99 | fileprivate func setupView() { 100 | 101 | // Self appearance 102 | self.autoresizingMask = [.flexibleHeight, .flexibleWidth] 103 | self.backgroundColor = UIColor.clear 104 | self.alpha = 0 105 | 106 | // Add subviews 107 | addSubview(blurView) 108 | addSubview(overlay) 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PresentationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogPresentationController.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | final internal class PresentationController: UIPresentationController { 30 | 31 | fileprivate lazy var overlay: PopupDialogOverlayView = { 32 | return PopupDialogOverlayView(frame: .zero) 33 | }() 34 | 35 | override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) { 36 | super.init(presentedViewController: presentedViewController, presenting: presentingViewController) 37 | overlay.blurView.underlyingView = presentingViewController?.view 38 | overlay.frame = (presentingViewController?.view.bounds)! 39 | } 40 | 41 | override func presentationTransitionWillBegin() { 42 | overlay.frame = containerView!.bounds 43 | containerView!.insertSubview(overlay, at: 0) 44 | 45 | presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (coordinatorContext) -> Void in 46 | self.overlay.alpha = 1.0 47 | }, completion: nil) 48 | } 49 | 50 | override func dismissalTransitionWillBegin() { 51 | presentedViewController.transitionCoordinator?.animate(alongsideTransition: { (coordinatorContext) -> Void in 52 | self.overlay.alpha = 0.0 53 | }, completion: nil) 54 | } 55 | 56 | override func containerViewWillLayoutSubviews() { 57 | presentedView!.frame = frameOfPresentedViewInContainerView 58 | overlay.blurView.setNeedsDisplay() 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/PresentationManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogPresentationManager.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | final internal class PresentationManager: NSObject, UIViewControllerTransitioningDelegate { 30 | 31 | var transitionStyle: PopupDialogTransitionStyle 32 | var interactor: InteractiveTransition 33 | 34 | init(transitionStyle: PopupDialogTransitionStyle, interactor: InteractiveTransition) { 35 | self.transitionStyle = transitionStyle 36 | self.interactor = interactor 37 | super.init() 38 | } 39 | 40 | func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { 41 | let presentationController = PresentationController(presentedViewController: presented, presenting: source) 42 | return presentationController 43 | } 44 | 45 | func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { 46 | 47 | var transition: TransitionAnimator 48 | switch transitionStyle { 49 | case .bounceUp: 50 | transition = BounceUpTransition(direction: .in) 51 | case .bounceDown: 52 | transition = BounceDownTransition(direction: .in) 53 | case .zoomIn: 54 | transition = ZoomTransition(direction: .in) 55 | case .fadeIn: 56 | transition = FadeTransition(direction: .in) 57 | } 58 | 59 | return transition 60 | } 61 | 62 | func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { 63 | 64 | if interactor.hasStarted || interactor.shouldFinish { 65 | return DismissInteractiveTransition() 66 | } 67 | 68 | var transition: TransitionAnimator 69 | switch transitionStyle { 70 | case .bounceUp: 71 | transition = BounceUpTransition(direction: .out) 72 | case .bounceDown: 73 | transition = BounceDownTransition(direction: .out) 74 | case .zoomIn: 75 | transition = ZoomTransition(direction: .out) 76 | case .fadeIn: 77 | transition = FadeTransition(direction: .out) 78 | } 79 | 80 | return transition 81 | } 82 | 83 | func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { 84 | return interactor.hasStarted ? interactor : nil 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TZStackView/TZSpacerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TZSpacerView.swift 3 | // TZStackView 4 | // 5 | // Created by Tom van Zummeren on 15/06/15. 6 | // Copyright © 2015 Tom van Zummeren. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class TZSpacerView: UIView { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TZStackView/TZStackView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TZStackView.swift 3 | // TZStackView 4 | // 5 | // Created by Tom van Zummeren on 10/06/15. 6 | // Copyright © 2015 Tom van Zummeren. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | struct TZAnimationDidStopQueueEntry: Equatable { 12 | let view: UIView 13 | let hidden: Bool 14 | } 15 | 16 | func ==(lhs: TZAnimationDidStopQueueEntry, rhs: TZAnimationDidStopQueueEntry) -> Bool { 17 | return lhs.view === rhs.view 18 | } 19 | 20 | public class TZStackView: UIView { 21 | 22 | public var distribution: TZStackViewDistribution = .fill { 23 | didSet { 24 | setNeedsUpdateConstraints() 25 | } 26 | } 27 | 28 | public var axis: UILayoutConstraintAxis = .horizontal { 29 | didSet { 30 | setNeedsUpdateConstraints() 31 | } 32 | } 33 | 34 | public var alignment: TZStackViewAlignment = .fill 35 | 36 | public var spacing: CGFloat = 0 37 | 38 | public var layoutMarginsRelativeArrangement = false 39 | 40 | public private(set) var arrangedSubviews: [UIView] = [] { 41 | didSet { 42 | setNeedsUpdateConstraints() 43 | registerHiddenListeners(oldValue) 44 | } 45 | } 46 | 47 | private var kvoContext = UInt8() 48 | 49 | private var stackViewConstraints = [NSLayoutConstraint]() 50 | private var subviewConstraints = [NSLayoutConstraint]() 51 | 52 | private var spacerViews = [UIView]() 53 | 54 | private var animationDidStopQueueEntries = [TZAnimationDidStopQueueEntry]() 55 | 56 | private var registeredKvoSubviews = [UIView]() 57 | 58 | private var animatingToHiddenViews = [UIView]() 59 | 60 | public init(arrangedSubviews: [UIView] = []) { 61 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) 62 | for arrangedSubview in arrangedSubviews { 63 | arrangedSubview.translatesAutoresizingMaskIntoConstraints = false 64 | addSubview(arrangedSubview) 65 | } 66 | 67 | // Closure to invoke didSet() 68 | { self.arrangedSubviews = arrangedSubviews }() 69 | } 70 | 71 | deinit { 72 | // This removes `hidden` value KVO observers using didSet() 73 | { self.arrangedSubviews = [] }() 74 | } 75 | 76 | private func registerHiddenListeners(_ previousArrangedSubviews: [UIView]) { 77 | for subview in previousArrangedSubviews { 78 | self.removeHiddenListener(subview) 79 | } 80 | 81 | for subview in arrangedSubviews { 82 | self.addHiddenListener(subview) 83 | } 84 | } 85 | 86 | private func addHiddenListener(_ view: UIView) { 87 | view.addObserver(self, forKeyPath: "hidden", options: [.old, .new], context: &kvoContext) 88 | registeredKvoSubviews.append(view) 89 | } 90 | 91 | private func removeHiddenListener(_ view: UIView) { 92 | if let index = registeredKvoSubviews.index(of: view) { 93 | view.removeObserver(self, forKeyPath: "hidden", context: &kvoContext) 94 | registeredKvoSubviews.remove(at: index) 95 | } 96 | } 97 | 98 | public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 99 | if let view = object as? UIView, let change = change, keyPath == "hidden" { 100 | let hidden = view.isHidden 101 | let previousValue = change[.oldKey] as! Bool 102 | if hidden == previousValue { 103 | return 104 | } 105 | if hidden { 106 | animatingToHiddenViews.append(view) 107 | } 108 | // Perform the animation 109 | setNeedsUpdateConstraints() 110 | setNeedsLayout() 111 | layoutIfNeeded() 112 | 113 | removeHiddenListener(view) 114 | view.isHidden = false 115 | 116 | if let _ = view.layer.animationKeys() { 117 | UIView.setAnimationDelegate(self) 118 | animationDidStopQueueEntries.insert(TZAnimationDidStopQueueEntry(view: view, hidden: hidden), at: 0) 119 | UIView.setAnimationDidStop(#selector(TZStackView.hiddenAnimationStopped)) 120 | } else { 121 | didFinishSettingHiddenValue(view, hidden: hidden) 122 | } 123 | } 124 | } 125 | 126 | private func didFinishSettingHiddenValue(_ arrangedSubview: UIView, hidden: Bool) { 127 | arrangedSubview.isHidden = hidden 128 | if let index = animatingToHiddenViews.index(of: arrangedSubview) { 129 | animatingToHiddenViews.remove(at: index) 130 | } 131 | addHiddenListener(arrangedSubview) 132 | } 133 | 134 | func hiddenAnimationStopped() { 135 | var queueEntriesToRemove = [TZAnimationDidStopQueueEntry]() 136 | for entry in animationDidStopQueueEntries { 137 | let view = entry.view 138 | if view.layer.animationKeys() == nil { 139 | didFinishSettingHiddenValue(view, hidden: entry.hidden) 140 | queueEntriesToRemove.append(entry) 141 | } 142 | } 143 | for entry in queueEntriesToRemove { 144 | if let index = animationDidStopQueueEntries.index(of: entry) { 145 | animationDidStopQueueEntries.remove(at: index) 146 | } 147 | } 148 | } 149 | 150 | public func addArrangedSubview(_ view: UIView) { 151 | view.translatesAutoresizingMaskIntoConstraints = false 152 | addSubview(view) 153 | arrangedSubviews.append(view) 154 | } 155 | 156 | public func removeArrangedSubview(_ view: UIView) { 157 | if let index = arrangedSubviews.index(of: view) { 158 | arrangedSubviews.remove(at: index) 159 | } 160 | } 161 | 162 | public func insertArrangedSubview(_ view: UIView, at stackIndex: Int) { 163 | view.translatesAutoresizingMaskIntoConstraints = false 164 | addSubview(view) 165 | arrangedSubviews.insert(view, at: stackIndex) 166 | } 167 | 168 | override public func willRemoveSubview(_ subview: UIView) { 169 | removeArrangedSubview(subview) 170 | } 171 | 172 | override public func updateConstraints() { 173 | removeConstraints(stackViewConstraints) 174 | stackViewConstraints.removeAll() 175 | 176 | for arrangedSubview in arrangedSubviews { 177 | arrangedSubview.removeConstraints(subviewConstraints) 178 | } 179 | subviewConstraints.removeAll() 180 | for arrangedSubview in arrangedSubviews { 181 | 182 | if alignment != .fill { 183 | let guideConstraint: NSLayoutConstraint 184 | switch axis { 185 | case .horizontal: 186 | guideConstraint = constraint(item: arrangedSubview, attribute: .height, toItem: nil, attribute: .notAnAttribute, constant: 0, priority: 25) 187 | case .vertical: 188 | guideConstraint = constraint(item: arrangedSubview, attribute: .width, toItem: nil, attribute: .notAnAttribute, constant: 0, priority: 25) 189 | } 190 | subviewConstraints.append(guideConstraint) 191 | arrangedSubview.addConstraint(guideConstraint) 192 | } 193 | 194 | if isHidden(arrangedSubview) { 195 | let hiddenConstraint: NSLayoutConstraint 196 | switch axis { 197 | case .horizontal: 198 | hiddenConstraint = constraint(item: arrangedSubview, attribute: .width, toItem: nil, attribute: .notAnAttribute, constant: 0) 199 | case .vertical: 200 | hiddenConstraint = constraint(item: arrangedSubview, attribute: .height, toItem: nil, attribute: .notAnAttribute, constant: 0) 201 | } 202 | subviewConstraints.append(hiddenConstraint) 203 | arrangedSubview.addConstraint(hiddenConstraint) 204 | } 205 | } 206 | 207 | for spacerView in spacerViews { 208 | spacerView.removeFromSuperview() 209 | } 210 | spacerViews.removeAll() 211 | 212 | if arrangedSubviews.count > 0 { 213 | 214 | let visibleArrangedSubviews = arrangedSubviews.filter({!self.isHidden($0)}) 215 | 216 | switch distribution { 217 | case .fillEqually, .fill, .fillProportionally: 218 | if alignment != .fill || layoutMarginsRelativeArrangement { 219 | _ = addSpacerView() 220 | } 221 | 222 | stackViewConstraints += createMatchEdgesContraints(arrangedSubviews) 223 | stackViewConstraints += createFirstAndLastViewMatchEdgesContraints() 224 | 225 | if alignment == .firstBaseline && axis == .horizontal { 226 | stackViewConstraints.append(constraint(item: self, attribute: .height, toItem: nil, attribute: .notAnAttribute, priority: 49)) 227 | } 228 | 229 | if distribution == .fillEqually { 230 | stackViewConstraints += createFillEquallyConstraints(arrangedSubviews) 231 | } 232 | if distribution == .fillProportionally { 233 | stackViewConstraints += createFillProportionallyConstraints(arrangedSubviews) 234 | } 235 | 236 | stackViewConstraints += createFillConstraints(arrangedSubviews, constant: spacing) 237 | case .equalSpacing: 238 | var views = [UIView]() 239 | var index = 0 240 | for arrangedSubview in arrangedSubviews { 241 | if isHidden(arrangedSubview) { 242 | continue 243 | } 244 | if index > 0 { 245 | views.append(addSpacerView()) 246 | } 247 | views.append(arrangedSubview) 248 | index += 1 249 | } 250 | if spacerViews.count == 0 { 251 | _ = addSpacerView() 252 | } 253 | 254 | stackViewConstraints += createMatchEdgesContraints(arrangedSubviews) 255 | stackViewConstraints += createFirstAndLastViewMatchEdgesContraints() 256 | 257 | switch axis { 258 | case .horizontal: 259 | stackViewConstraints.append(constraint(item: self, attribute: .width, toItem: nil, attribute: .notAnAttribute, priority: 49)) 260 | if alignment == .firstBaseline { 261 | stackViewConstraints.append(constraint(item: self, attribute: .height, toItem: nil, attribute: .notAnAttribute, priority: 49)) 262 | } 263 | case .vertical: 264 | stackViewConstraints.append(constraint(item: self, attribute: .height, toItem: nil, attribute: .notAnAttribute, priority: 49)) 265 | } 266 | 267 | stackViewConstraints += createFillConstraints(views, constant: 0) 268 | stackViewConstraints += createFillEquallyConstraints(spacerViews) 269 | stackViewConstraints += createFillConstraints(arrangedSubviews, relatedBy: .greaterThanOrEqual, constant: spacing) 270 | case .equalCentering: 271 | for (index, _) in visibleArrangedSubviews.enumerated() { 272 | if index > 0 { 273 | _ = addSpacerView() 274 | } 275 | } 276 | if spacerViews.count == 0 { 277 | _ = addSpacerView() 278 | } 279 | 280 | stackViewConstraints += createMatchEdgesContraints(arrangedSubviews) 281 | stackViewConstraints += createFirstAndLastViewMatchEdgesContraints() 282 | 283 | switch axis { 284 | case .horizontal: 285 | stackViewConstraints.append(constraint(item: self, attribute: .width, toItem: nil, attribute: .notAnAttribute, priority: 49)) 286 | if alignment == .firstBaseline { 287 | stackViewConstraints.append(constraint(item: self, attribute: .height, toItem: nil, attribute: .notAnAttribute, priority: 49)) 288 | } 289 | case .vertical: 290 | stackViewConstraints.append(constraint(item: self, attribute: .height, toItem: nil, attribute: .notAnAttribute, priority: 49)) 291 | } 292 | 293 | var previousArrangedSubview: UIView? 294 | for (index, arrangedSubview) in visibleArrangedSubviews.enumerated() { 295 | if let previousArrangedSubview = previousArrangedSubview { 296 | let spacerView = spacerViews[index - 1] 297 | 298 | switch axis { 299 | case .horizontal: 300 | stackViewConstraints.append(constraint(item: previousArrangedSubview, attribute: .centerX, toItem: spacerView, attribute: .leading)) 301 | stackViewConstraints.append(constraint(item: arrangedSubview, attribute: .centerX, toItem: spacerView, attribute: .trailing)) 302 | case .vertical: 303 | stackViewConstraints.append(constraint(item: previousArrangedSubview, attribute: .centerY, toItem: spacerView, attribute: .top)) 304 | stackViewConstraints.append(constraint(item: arrangedSubview, attribute: .centerY, toItem: spacerView, attribute: .bottom)) 305 | } 306 | } 307 | previousArrangedSubview = arrangedSubview 308 | } 309 | 310 | stackViewConstraints += createFillEquallyConstraints(spacerViews, priority: 150) 311 | stackViewConstraints += createFillConstraints(arrangedSubviews, relatedBy: .greaterThanOrEqual, constant: spacing) 312 | } 313 | 314 | if spacerViews.count > 0 { 315 | stackViewConstraints += createSurroundingSpacerViewConstraints(spacerViews[0], views: visibleArrangedSubviews) 316 | } 317 | 318 | if layoutMarginsRelativeArrangement { 319 | if spacerViews.count > 0 { 320 | stackViewConstraints.append(constraint(item: self, attribute: .bottomMargin, toItem: spacerViews[0], attribute: .bottom)) 321 | stackViewConstraints.append(constraint(item: self, attribute: .leftMargin, toItem: spacerViews[0], attribute: .left)) 322 | stackViewConstraints.append(constraint(item: self, attribute: .rightMargin, toItem: spacerViews[0], attribute: .right)) 323 | stackViewConstraints.append(constraint(item: self, attribute: .topMargin, toItem: spacerViews[0], attribute: .top)) 324 | } 325 | } 326 | addConstraints(stackViewConstraints) 327 | } 328 | 329 | super.updateConstraints() 330 | } 331 | 332 | required public init(coder aDecoder: NSCoder) { 333 | super.init(coder: aDecoder)! 334 | } 335 | 336 | private func addSpacerView() -> TZSpacerView { 337 | let spacerView = TZSpacerView() 338 | spacerView.translatesAutoresizingMaskIntoConstraints = false 339 | 340 | spacerViews.append(spacerView) 341 | insertSubview(spacerView, at: 0) 342 | return spacerView 343 | } 344 | 345 | private func createSurroundingSpacerViewConstraints(_ spacerView: UIView, views: [UIView]) -> [NSLayoutConstraint] { 346 | if alignment == .fill { 347 | return [] 348 | } 349 | 350 | var topPriority: Float = 1000 351 | var topRelation: NSLayoutRelation = .lessThanOrEqual 352 | 353 | var bottomPriority: Float = 1000 354 | var bottomRelation: NSLayoutRelation = .greaterThanOrEqual 355 | 356 | if alignment == .top || alignment == .leading { 357 | topPriority = 999.5 358 | topRelation = .equal 359 | } 360 | 361 | if alignment == .bottom || alignment == .trailing { 362 | bottomPriority = 999.5 363 | bottomRelation = .equal 364 | } 365 | 366 | var constraints = [NSLayoutConstraint]() 367 | for view in views { 368 | switch axis { 369 | case .horizontal: 370 | constraints.append(constraint(item: spacerView, attribute: .top, relatedBy: topRelation, toItem: view, priority: topPriority)) 371 | constraints.append(constraint(item: spacerView, attribute: .bottom, relatedBy: bottomRelation, toItem: view, priority: bottomPriority)) 372 | case .vertical: 373 | constraints.append(constraint(item: spacerView, attribute: .leading, relatedBy: topRelation, toItem: view, priority: topPriority)) 374 | constraints.append(constraint(item: spacerView, attribute: .trailing, relatedBy: bottomRelation, toItem: view, priority: bottomPriority)) 375 | } 376 | } 377 | switch axis { 378 | case .horizontal: 379 | constraints.append(constraint(item: spacerView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, constant: 0, priority: 51)) 380 | case .vertical: 381 | constraints.append(constraint(item: spacerView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, constant: 0, priority: 51)) 382 | } 383 | return constraints 384 | } 385 | 386 | private func createFillProportionallyConstraints(_ views: [UIView]) -> [NSLayoutConstraint] { 387 | var constraints = [NSLayoutConstraint]() 388 | 389 | var totalSize: CGFloat = 0 390 | var totalCount = 0 391 | for arrangedSubview in views { 392 | if isHidden(arrangedSubview) { 393 | continue 394 | } 395 | switch axis { 396 | case .horizontal: 397 | totalSize += arrangedSubview.intrinsicContentSize.width 398 | case .vertical: 399 | totalSize += arrangedSubview.intrinsicContentSize.height 400 | } 401 | totalCount += 1 402 | } 403 | totalSize += (CGFloat(totalCount - 1) * spacing) 404 | 405 | var priority: Float = 1000 406 | let countDownPriority = (views.filter({!self.isHidden($0)}).count > 1) 407 | for arrangedSubview in views { 408 | if countDownPriority { 409 | priority -= 1 410 | } 411 | 412 | if isHidden(arrangedSubview) { 413 | continue 414 | } 415 | switch axis { 416 | case .horizontal: 417 | let multiplier = arrangedSubview.intrinsicContentSize.width / totalSize 418 | constraints.append(constraint(item: arrangedSubview, attribute: .width, toItem: self, multiplier: multiplier, priority: priority)) 419 | case .vertical: 420 | let multiplier = arrangedSubview.intrinsicContentSize.height / totalSize 421 | constraints.append(constraint(item: arrangedSubview, attribute: .height, toItem: self, multiplier: multiplier, priority: priority)) 422 | } 423 | } 424 | 425 | return constraints 426 | } 427 | 428 | // Matchs all Width or Height attributes of all given views 429 | private func createFillEquallyConstraints(_ views: [UIView], priority: Float = 1000) -> [NSLayoutConstraint] { 430 | switch axis { 431 | case .horizontal: 432 | return equalAttributes(views: views.filter({ !self.isHidden($0) }), attribute: .width, priority: priority) 433 | 434 | case .vertical: 435 | return equalAttributes(views: views.filter({ !self.isHidden($0) }), attribute: .height, priority: priority) 436 | } 437 | } 438 | 439 | // Chains together the given views using Leading/Trailing or Top/Bottom 440 | private func createFillConstraints(_ views: [UIView], priority: Float = 1000, relatedBy relation: NSLayoutRelation = .equal, constant: CGFloat) -> [NSLayoutConstraint] { 441 | var constraints = [NSLayoutConstraint]() 442 | 443 | var previousView: UIView? 444 | for view in views { 445 | if let previousView = previousView { 446 | var c: CGFloat = 0 447 | if !isHidden(previousView) && !isHidden(view) { 448 | c = constant 449 | } else if isHidden(previousView) && !isHidden(view) && views.first != previousView { 450 | c = (constant / 2) 451 | } else if isHidden(view) && !isHidden(previousView) && views.last != view { 452 | c = (constant / 2) 453 | } 454 | switch axis { 455 | case .horizontal: 456 | constraints.append(constraint(item: view, attribute: .leading, relatedBy: relation, toItem: previousView, attribute: .trailing, constant: c, priority: priority)) 457 | 458 | case .vertical: 459 | constraints.append(constraint(item: view, attribute: .top, relatedBy: relation, toItem: previousView, attribute: .bottom, constant: c, priority: priority)) 460 | } 461 | } 462 | previousView = view 463 | } 464 | return constraints 465 | } 466 | 467 | // Matches all Bottom/Top or Leading Trailing constraints of te given views and matches those attributes of the first/last view to the container 468 | private func createMatchEdgesContraints(_ views: [UIView]) -> [NSLayoutConstraint] { 469 | var constraints = [NSLayoutConstraint]() 470 | 471 | switch axis { 472 | case .horizontal: 473 | switch alignment { 474 | case .fill: 475 | constraints += equalAttributes(views: views, attribute: .bottom) 476 | constraints += equalAttributes(views: views, attribute: .top) 477 | case .center: 478 | constraints += equalAttributes(views: views, attribute: .centerY) 479 | case .leading, .top: 480 | constraints += equalAttributes(views: views, attribute: .top) 481 | case .trailing, .bottom: 482 | constraints += equalAttributes(views: views, attribute: .bottom) 483 | case .firstBaseline: 484 | constraints += equalAttributes(views: views, attribute: .firstBaseline) 485 | } 486 | 487 | case .vertical: 488 | switch alignment { 489 | case .fill: 490 | constraints += equalAttributes(views: views, attribute: .leading) 491 | constraints += equalAttributes(views: views, attribute: .trailing) 492 | case .center: 493 | constraints += equalAttributes(views: views, attribute: .centerX) 494 | case .leading, .top: 495 | constraints += equalAttributes(views: views, attribute: .leading) 496 | case .trailing, .bottom: 497 | constraints += equalAttributes(views: views, attribute: .trailing) 498 | case .firstBaseline: 499 | constraints += [] 500 | } 501 | } 502 | return constraints 503 | } 504 | 505 | private func createFirstAndLastViewMatchEdgesContraints() -> [NSLayoutConstraint] { 506 | 507 | var constraints = [NSLayoutConstraint]() 508 | 509 | let visibleViews = arrangedSubviews.filter({!self.isHidden($0)}) 510 | let firstView = visibleViews.first 511 | let lastView = visibleViews.last 512 | 513 | var topView = arrangedSubviews.first! 514 | var bottomView = arrangedSubviews.first! 515 | if spacerViews.count > 0 { 516 | if alignment == .center { 517 | topView = spacerViews[0] 518 | bottomView = spacerViews[0] 519 | } else if alignment == .top || alignment == .leading { 520 | bottomView = spacerViews[0] 521 | } else if alignment == .bottom || alignment == .trailing { 522 | topView = spacerViews[0] 523 | } else if alignment == .firstBaseline { 524 | switch axis { 525 | case .horizontal: 526 | bottomView = spacerViews[0] 527 | case .vertical: 528 | topView = spacerViews[0] 529 | bottomView = spacerViews[0] 530 | } 531 | } 532 | } 533 | 534 | let firstItem = layoutMarginsRelativeArrangement ? spacerViews[0] : self 535 | 536 | switch axis { 537 | case .horizontal: 538 | if let firstView = firstView { 539 | constraints.append(constraint(item: firstItem, attribute: .leading, toItem: firstView)) 540 | } 541 | if let lastView = lastView { 542 | constraints.append(constraint(item: firstItem, attribute: .trailing, toItem: lastView)) 543 | } 544 | 545 | constraints.append(constraint(item: firstItem, attribute: .top, toItem: topView)) 546 | constraints.append(constraint(item: firstItem, attribute: .bottom, toItem: bottomView)) 547 | 548 | if alignment == .center { 549 | constraints.append(constraint(item: firstItem, attribute: .centerY, toItem: arrangedSubviews.first!)) 550 | } 551 | case .vertical: 552 | if let firstView = firstView { 553 | constraints.append(constraint(item: firstItem, attribute: .top, toItem: firstView)) 554 | } 555 | if let lastView = lastView { 556 | constraints.append(constraint(item: firstItem, attribute: .bottom, toItem: lastView)) 557 | } 558 | 559 | constraints.append(constraint(item: firstItem, attribute: .leading, toItem: topView)) 560 | constraints.append(constraint(item: firstItem, attribute: .trailing, toItem: bottomView)) 561 | 562 | if alignment == .center { 563 | constraints.append(constraint(item: firstItem, attribute: .centerX, toItem: arrangedSubviews.first!)) 564 | } 565 | } 566 | 567 | return constraints 568 | } 569 | 570 | private func equalAttributes(views: [UIView], attribute: NSLayoutAttribute, priority: Float = 1000) -> [NSLayoutConstraint] { 571 | var currentPriority = priority 572 | var constraints = [NSLayoutConstraint]() 573 | if views.count > 0 { 574 | 575 | var firstView: UIView? 576 | 577 | let countDownPriority = (currentPriority < 1000) 578 | for view in views { 579 | if let firstView = firstView { 580 | constraints.append(constraint(item: firstView, attribute: attribute, toItem: view, priority: currentPriority)) 581 | } else { 582 | firstView = view 583 | } 584 | if countDownPriority { 585 | currentPriority -= 1 586 | } 587 | } 588 | } 589 | return constraints 590 | } 591 | 592 | // Convenience method to help make NSLayoutConstraint in a less verbose way 593 | private func constraint(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation = .equal, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute? = nil, multiplier: CGFloat = 1, constant c: CGFloat = 0, priority: Float = 1000) -> NSLayoutConstraint { 594 | 595 | let attribute2 = attr2 != nil ? attr2! : attr1 596 | 597 | let constraint = NSLayoutConstraint(item: view1, attribute: attr1, relatedBy: relation, toItem: view2, attribute: attribute2, multiplier: multiplier, constant: c) 598 | constraint.priority = priority 599 | return constraint 600 | } 601 | 602 | private func isHidden(_ view: UIView) -> Bool { 603 | if view.isHidden { 604 | return true 605 | } 606 | return animatingToHiddenViews.index(of: view) != nil 607 | } 608 | } 609 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TZStackView/TZStackViewAlignment.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TZStackViewAlignment.swift 3 | // TZStackView 4 | // 5 | // Created by Tom van Zummeren on 15/06/15. 6 | // Copyright © 2015 Tom van Zummeren. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @objc public enum TZStackViewAlignment: Int { 12 | case fill 13 | case center 14 | case leading 15 | case top 16 | case trailing 17 | case bottom 18 | case firstBaseline 19 | } 20 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TZStackView/TZStackViewDistribution.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TZStackViewDistribution.swift 3 | // TZStackView 4 | // 5 | // Created by Tom van Zummeren on 10/06/15. 6 | // Copyright © 2015 Tom van Zummeren. All rights reserved. 7 | // 8 | import Foundation 9 | 10 | @objc public enum TZStackViewDistribution: Int { 11 | case fill 12 | case fillEqually 13 | case fillProportionally 14 | case equalSpacing 15 | case equalCentering 16 | } 17 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TransitionAnimations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogTransitionAnimations.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /*! 30 | Presentation transition styles for the popup dialog 31 | 32 | - BounceUp: Dialog bounces in from bottom and is dismissed to bottom 33 | - BounceDown: Dialog bounces in from top and is dismissed to top 34 | - ZoomIn: Dialog zooms in and is dismissed by zooming out 35 | - FadeIn: Dialog fades in and is dismissed by fading out 36 | */ 37 | @objc public enum PopupDialogTransitionStyle: Int { 38 | case bounceUp 39 | case bounceDown 40 | case zoomIn 41 | case fadeIn 42 | } 43 | 44 | /// Dialog bounces in from bottom and is dismissed to bottom 45 | final internal class BounceUpTransition: TransitionAnimator { 46 | 47 | init(direction: AnimationDirection) { 48 | super.init(inDuration: 0.22, outDuration: 0.2, direction: direction) 49 | } 50 | 51 | override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 52 | super.animateTransition(using: transitionContext) 53 | 54 | switch direction { 55 | case .in: 56 | to.view.bounds.origin = CGPoint(x: 0, y: -from.view.bounds.size.height) 57 | UIView.animate(withDuration: 0.6, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: [.curveEaseOut], animations: { 58 | self.to.view.bounds = self.from.view.bounds 59 | }) { (completed) in 60 | transitionContext.completeTransition(completed) 61 | } 62 | case .out: 63 | UIView.animate(withDuration: outDuration, delay: 0.0, options: [.curveEaseIn], animations: { 64 | self.from.view.bounds.origin = CGPoint(x: 0, y: -self.from.view.bounds.size.height) 65 | self.from.view.alpha = 0.0 66 | }) { (completed) in 67 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 68 | } 69 | } 70 | } 71 | } 72 | 73 | 74 | /// Dialog bounces in from top and is dismissed to top 75 | final internal class BounceDownTransition: TransitionAnimator { 76 | 77 | init(direction: AnimationDirection) { 78 | super.init(inDuration: 0.22, outDuration: 0.2, direction: direction) 79 | } 80 | 81 | override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 82 | super.animateTransition(using: transitionContext) 83 | 84 | switch direction { 85 | case .in: 86 | to.view.bounds.origin = CGPoint(x: 0, y: from.view.bounds.size.height) 87 | UIView.animate(withDuration: 0.6, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: [.curveEaseOut], animations: { 88 | self.to.view.bounds = self.from.view.bounds 89 | }) { (completed) in 90 | transitionContext.completeTransition(completed) 91 | } 92 | case .out: 93 | UIView.animate(withDuration: outDuration, delay: 0.0, options: [.curveEaseIn], animations: { 94 | self.from.view.bounds.origin = CGPoint(x: 0, y: self.from.view.bounds.size.height) 95 | self.from.view.alpha = 0.0 96 | }) { (completed) in 97 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 98 | } 99 | } 100 | } 101 | } 102 | 103 | /// Dialog zooms in and is dismissed by zooming out 104 | final internal class ZoomTransition: TransitionAnimator { 105 | 106 | init(direction: AnimationDirection) { 107 | super.init(inDuration: 0.22, outDuration: 0.2, direction: direction) 108 | } 109 | 110 | override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 111 | super.animateTransition(using: transitionContext) 112 | 113 | switch direction { 114 | case .in: 115 | to.view.transform = CGAffineTransform(scaleX: 0.1, y: 0.1) 116 | UIView.animate(withDuration: 0.6, delay: 0.0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: [.curveEaseOut], animations: { 117 | self.to.view.transform = CGAffineTransform(scaleX: 1, y: 1) 118 | }) { (completed) in 119 | transitionContext.completeTransition(completed) 120 | } 121 | case .out: 122 | UIView.animate(withDuration: outDuration, delay: 0.0, options: [.curveEaseIn], animations: { 123 | self.from.view.transform = CGAffineTransform(scaleX: 0.1, y: 0.1) 124 | self.from.view.alpha = 0.0 125 | }) { (completed) in 126 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 127 | } 128 | } 129 | } 130 | } 131 | 132 | /// Dialog fades in and is dismissed by fading out 133 | final internal class FadeTransition: TransitionAnimator { 134 | 135 | init(direction: AnimationDirection) { 136 | super.init(inDuration: 0.22, outDuration: 0.2, direction: direction) 137 | } 138 | 139 | override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 140 | super.animateTransition(using: transitionContext) 141 | 142 | switch direction { 143 | case .in: 144 | to.view.alpha = 0 145 | UIView.animate(withDuration: 0.6, delay: 0.0, options: [.curveEaseOut], 146 | animations: { 147 | self.to.view.alpha = 1 148 | }) { (completed) in 149 | transitionContext.completeTransition(completed) 150 | } 151 | case .out: 152 | UIView.animate(withDuration: outDuration, delay: 0.0, options: [.curveEaseIn], animations: { 153 | self.from.view.alpha = 0.0 154 | }) { (completed) in 155 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 156 | } 157 | } 158 | } 159 | } 160 | 161 | /// Used for the always drop out animation with pan gesture dismissal 162 | final internal class DismissInteractiveTransition: TransitionAnimator { 163 | 164 | init() { 165 | super.init(inDuration: 0.22, outDuration: 0.32, direction: .out) 166 | } 167 | 168 | override func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 169 | super.animateTransition(using: transitionContext) 170 | UIView.animate(withDuration: outDuration, delay: 0.0, options: [.beginFromCurrentState], animations: { 171 | self.from.view.bounds.origin = CGPoint(x: 0, y: -self.from.view.bounds.size.height) 172 | self.from.view.alpha = 0.0 173 | }) { (completed) in 174 | transitionContext.completeTransition(!transitionContext.transitionWasCancelled) 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/TransitionAnimator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupDialogTransitionAnimator.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /// Base class for custom transition animations 30 | internal class TransitionAnimator: NSObject, UIViewControllerAnimatedTransitioning { 31 | 32 | var to: UIViewController! 33 | var from: UIViewController! 34 | let inDuration: TimeInterval 35 | let outDuration: TimeInterval 36 | let direction: AnimationDirection 37 | 38 | init(inDuration: TimeInterval, outDuration: TimeInterval, direction: AnimationDirection) { 39 | self.inDuration = inDuration 40 | self.outDuration = outDuration 41 | self.direction = direction 42 | super.init() 43 | } 44 | 45 | internal func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 46 | return direction == .in ? inDuration : outDuration 47 | } 48 | 49 | internal func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { 50 | switch direction { 51 | case .in: 52 | to = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)! 53 | from = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)! 54 | let container = transitionContext.containerView 55 | container.addSubview(to.view) 56 | case .out: 57 | to = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)! 58 | from = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)! 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/UIImageView+Calculations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIImageView+Calculations.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | internal extension UIImageView { 30 | 31 | /*! 32 | Calculates the height of the the UIImageView has to 33 | have so the image is displayed correctly 34 | - returns: Height to set on the imageView 35 | */ 36 | internal func pv_heightForImageView() -> CGFloat { 37 | guard let image = image, image.size.height > 0 else { 38 | return 0.0 39 | } 40 | let width = bounds.size.width 41 | let ratio = image.size.height / image.size.width 42 | return width * ratio 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/UIView+Animations.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Animations.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | /*! 30 | The intended direction of the animation 31 | - in: Animate in 32 | - out: Animate out 33 | */ 34 | internal enum AnimationDirection { 35 | case `in` 36 | case out 37 | } 38 | 39 | internal extension UIView { 40 | 41 | /// The key for the fade animation 42 | internal var fadeKey: String { return "FadeAnimation" } 43 | 44 | /*! 45 | Applies a fade animation to this view 46 | - parameter direction: Animation direction 47 | - parameter value: The end value of this animation 48 | - parameter duration: The duration of this animation 49 | */ 50 | internal func pv_fade(_ direction: AnimationDirection, _ value: Float, duration: CFTimeInterval = 0.08) { 51 | layer.removeAnimation(forKey: fadeKey) 52 | let animation = CABasicAnimation(keyPath: "opacity") 53 | animation.duration = duration 54 | animation.fromValue = layer.presentation()?.opacity 55 | layer.opacity = value 56 | animation.fillMode = kCAFillModeForwards 57 | layer.add(animation, forKey: fadeKey) 58 | } 59 | 60 | internal func pv_layoutIfNeededAnimated(duration: CFTimeInterval = 0.08) { 61 | UIView.animate(withDuration: duration, delay: 0, options: UIViewAnimationOptions(), animations: { 62 | self.layoutIfNeeded() 63 | }, completion: nil) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Pods/PopupDialog/PopupDialog/Classes/UIViewController+Visibility.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+Visibility.swift 3 | // 4 | // Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 5 | // Author - Martin Wildfeuer (http://www.mwfire.de) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | 26 | import Foundation 27 | import UIKit 28 | 29 | // http://stackoverflow.com/questions/2777438/how-to-tell-if-uiviewcontrollers-view-is-visible 30 | internal extension UIViewController { 31 | 32 | internal var isTopAndVisible: Bool { 33 | return isVisible && isTopViewController 34 | } 35 | 36 | internal var isVisible: Bool { 37 | if isViewLoaded { 38 | return view.window != nil 39 | } 40 | return false 41 | } 42 | 43 | internal var isTopViewController: Bool { 44 | if self.navigationController != nil { 45 | return self.navigationController?.visibleViewController === self 46 | } else if self.tabBarController != nil { 47 | return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil 48 | } else { 49 | return self.presentedViewController == nil && self.isVisible 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Pods/PopupDialog/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 |

 

4 | 5 | [![Version](https://img.shields.io/cocoapods/v/PopupDialog.svg?style=flat)](http://cocoapods.org/pods/PopupDialog) 6 | [![License](https://img.shields.io/cocoapods/l/PopupDialog.svg?style=flat)](http://cocoapods.org/pods/PopupDialog) 7 | [![Platform](https://img.shields.io/cocoapods/p/PopupDialog.svg?style=flat)](http://cocoapods.org/pods/PopupDialog) 8 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 9 | [![codebeat badge](https://codebeat.co/badges/006f8d13-072a-42bb-a584-6b97e60201e1)](https://codebeat.co/projects/github-com-orderella-popupdialog) 10 | [![Build Status Master](https://travis-ci.org/Orderella/PopupDialog.svg?branch=master)](https://travis-ci.org/Orderella/PopupDialog) 11 | [![Build Status Development](https://travis-ci.org/Orderella/PopupDialog.svg?branch=development)](https://travis-ci.org/Orderella/PopupDialog) 12 | 13 |

 

14 | 15 | # Introduction 16 | 17 | Popup Dialog is a simple, customizable popup dialog written in Swift. 18 | 19 | 20 | 21 | 22 | 23 | ## Features 24 | 25 | - [x] Easy to use API with hardly any boilerplate code 26 | - [x] Convenient default view with image, title, message 27 | - [x] Supports custom view controllers 28 | - [x] Slick transition animations 29 | - [x] Fully themeable via appearance, including fonts, colors, corner radius, shadow, overlay color and blur, etc. 30 | - [x] Can be dismissed via swipe and background tap 31 | - [x] Objective-C compatible 32 | - [x] Works on all screens and devices supporting iOS 8.0+ 33 | 34 |

 

35 | 36 | # Installation 37 | 38 | ## Cocoapods 39 | 40 | PopupDialog is available through [CocoaPods](http://cocoapods.org). For best results with Swift 3, I recommend 41 | installing CocoaPods version `1.1.0` (which might be a prerelease as of this release). Simply add the following to your Podfile: 42 | 43 | ```ruby 44 | use_frameworks! 45 | 46 | target '' 47 | pod 'PopupDialog', '~> 0.5' 48 | ``` 49 | 50 | **Please note that this version is compatiable with iOS8** 51 | 52 | ## Carthage 53 | 54 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. A minimum version of `0.17` is required. 55 | 56 | To install, simply add the following lines to your Cartfile: 57 | 58 | ```ruby 59 | github "Orderella/PopupDialog" ~> 0.5 60 | ``` 61 | 62 | ## Manually 63 | 64 | If you prefer not to use either of the above mentioned dependency managers, you can integrate PopupDialog into your project manually by adding the files contained in the [Classes](https://github.com/trungp/PopupDialog/tree/master/PopupDialog/Classes) 65 | folder to your project. 66 | 67 | 68 |

 

69 | 70 | # Example 71 | 72 | You can find this and more example projects in the repo. To run it, clone the repo, and run `pod install` from the Example directory first. 73 | 74 | ```swift 75 | import PopupDialog 76 | 77 | // Prepare the popup assets 78 | let title = "THIS IS THE DIALOG TITLE" 79 | let message = "This is the message section of the popup dialog default view" 80 | let image = UIImage(named: "pexels-photo-103290") 81 | 82 | // Create the dialog 83 | let popup = PopupDialog(title: title, message: message, image: image) 84 | 85 | // Create buttons 86 | let buttonOne = CancelButton(title: "CANCEL") { 87 | print("You canceled the car dialog.") 88 | } 89 | 90 | let buttonTwo = DefaultButton(title: "ADMIRE CAR") { 91 | print("What a beauty!") 92 | } 93 | 94 | let buttonThree = DefaultButton(title: "BUY CAR", height: 60) { 95 | print("Ah, maybe next time :)") 96 | } 97 | 98 | // Add buttons to dialog 99 | // Alternatively, you can use popup.addButton(buttonOne) 100 | // to add a single button 101 | popup.addButtons([buttonOne, buttonTwo, buttonThree]) 102 | 103 | // Present dialog 104 | self.present(popup, animated: true, completion: nil) 105 | ``` 106 | 107 |

 

108 | 109 | # Usage 110 | 111 | PopupDialog is a subclass of UIViewController and as such can be added to your view controller modally. You can initialize it either with the handy default view or a custom view controller. 112 | 113 | ## Default Dialog 114 | 115 | ```swift 116 | public convenience init( 117 | title: String?, 118 | message: String?, 119 | image: UIImage? = nil, 120 | buttonAlignment: UILayoutConstraintAxis = .vertical, 121 | transitionStyle: PopupDialogTransitionStyle = .bounceUp, 122 | gestureDismissal: Bool = true, 123 | completion: (() -> Void)? = nil) 124 | ``` 125 | 126 | The default dialog initializer is a convenient way of creating a popup with image, title and message (see image one and two). 127 | 128 | Bascially, all parameters are optional, although this makes no sense at all. You want to at least add a message and a single button, otherwise the dialog can't be dismissed, unless you do it manually. 129 | 130 | If you provide an image it will be pinned to the top/left/right of the dialog. The ratio of the image will be used to set the height of the image view, so no distortion will occur. 131 | 132 | ## Custom View Controller 133 | 134 | ```swift 135 | public init( 136 | viewController: UIViewController, 137 | buttonAlignment: UILayoutConstraintAxis = .vertical, 138 | transitionStyle: PopupDialogTransitionStyle = .bounceUp, 139 | gestureDismissal: Bool = true, 140 | completion: (() -> Void)? = nil) 141 | ``` 142 | 143 | You can pass your own view controller to PopupDialog (see image three). It is accessible via the `viewController` property of PopupDialog, which has to be casted to your view controllers class to access its properties. Make sure the custom view defines all constraints needed, so you don't run into any autolayout issues. 144 | 145 | Buttons are added below the controllers view, however, these buttons are optional. If you decide to not add any buttons, you have to take care of dismissing the dialog manually. Being a subclass of view controller, this can be easily done via `dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)?)`. 146 | 147 | ## Transition Animations 148 | 149 | You can set a transition animation style with `.BounceUp` being the default. The following transition styles are available 150 | 151 | ```swift 152 | public enum PopupDialogTransitionStyle: Int { 153 | case bounceUp 154 | case bounceDown 155 | case zoomIn 156 | case fadeIn 157 | } 158 | ``` 159 | 160 | ## Button Alignment 161 | 162 | Buttons can be distributed either `.Horizontal` or `.Vertical`, with the latter being the default. Please note distributing buttons horizontally might not be a good idea if you have more than two buttons. 163 | 164 | ```swift 165 | public enum UILayoutConstraintAxis : Int { 166 | case horizontal 167 | case vertical 168 | } 169 | ``` 170 | 171 | ## Gesture Dismissal 172 | 173 | Gesture dismissal allows your dialog being dismissed either by a background tap or by swiping the dialog down. By default, this is set to `true`. You can prevent this behavior by setting `gestureDismissal` to `false` in the initializer. 174 | 175 | ## Completion 176 | This completion handler is called when the dialog was dismissed. This is especially useful for catching a gesture dismissal. 177 | 178 |

 

179 | 180 | # Default Dialog Properties 181 | 182 | If you are using the default dialog, you can change selected properties at runtime: 183 | 184 | ```swift 185 | // Create the dialog 186 | let popup = PopupDialog(title: title, message: message, image: image) 187 | 188 | // Present dialog 189 | self.presentViewController(popup, animated: true, completion: nil) 190 | 191 | // Get the default view controller and cast it 192 | // Unfortunately, casting is necessary to support Objective-C 193 | let vc = popup.viewController as! PopupDialogDefaultViewController 194 | 195 | // Set dialog properties 196 | vc.image = UIImage(...) 197 | vc.titleText = "..." 198 | vc.messageText = "..." 199 | vc.buttonAlignment = .horizontal 200 | vc.transitionStyle = .bounceUp 201 | ``` 202 | 203 |

 

204 | 205 | # Styling PopupDialog 206 | 207 | Appearance is the preferred way of customizing the style of PopupDialog. 208 | The idea of PopupDialog is to define a theme in a single place, without having to provide style settings with every single instantiation. This way, creating a PopupDialog requires only minimal code to be written and no "wrappers". 209 | 210 | This makes even more sense, as popup dialogs and alerts are supposed to look consistent throughout the app, that is, maintain a single style. 211 | 212 | ## Dialog Default View Appearance Settings 213 | 214 | If you are using the default popup view, the following appearance settings are available: 215 | 216 | ```swift 217 | var dialogAppearance = PopupDialogDefaultView.appearance() 218 | 219 | dialogAppearance.backgroundColor = UIColor.white 220 | dialogAppearance.titleFont = UIFont.boldSystemFont(ofSize: 14) 221 | dialogAppearance.titleColor = UIColor(white: 0.4, alpha: 1) 222 | dialogAppearance.titleTextAlignment = .center 223 | dialogAppearance.messageFont = UIFont.systemFont(ofSize: 14) 224 | dialogAppearance.messageColor = UIColor(white: 0.6, alpha: 1) 225 | dialogAppearance.messageTextAlignment = .center 226 | dialogAppearance.cornerRadius = 4 227 | dialogAppearance.shadowEnabled = true 228 | dialogAppearance.shadowColor = UIColor.black 229 | ``` 230 | 231 | ## Overlay View Appearance Settings 232 | 233 | This refers to the view that is used as an overlay above the underlying view controller but below the popup dialog view. If that makes sense ;) 234 | 235 | ```swift 236 | let overlayAppearance = PopupDialogOverlayView.appearance() 237 | 238 | overlayAppearance.color = UIColor.black 239 | overlayAppearance.blurRadius = 20 240 | overlayAppearance.blurEnabled = true 241 | overlayAppearance.liveBlur = false 242 | overlayAppearance.opacity = 0.7 243 | ``` 244 | 245 | #### Note 246 | Turning on `liveBlur`, that is realtime updates of the background view, results in a significantly higher CPU usage /power consumption and is therefore turned off by default now. 247 | Choose wisely whether you need this feature or not ;) 248 | 249 | ## Button Appearance Settings 250 | 251 | The standard button classes available are `DefaultButton`, `CancelButton` and `DestructiveButton`. All buttons feature the same appearance settings and can be styled seperately. 252 | 253 | ```swift 254 | var buttonAppearance = DefaultButton.appearance() 255 | 256 | // Default button 257 | buttonAppearance.titleFont = UIFont.systemFont(ofSize: 14) 258 | buttonAppearance.titleColor = UIColor(red: 0.25, green: 0.53, blue: 0.91, alpha: 1) 259 | buttonAppearance.buttonColor = UIColor.clear 260 | buttonAppearance.separatorColor = UIColor(white: 0.9, alpha: 1) 261 | 262 | // Below, only the differences are highlighted 263 | 264 | // Cancel button 265 | CancelButton.appearance().titleColor = UIColor.lightGray 266 | 267 | // Destructive button 268 | DestructiveButton.appearance().titleColor = UIColor.red 269 | ``` 270 | 271 | Moreover, you can create a custom button by subclassing `PopupDialogButton`. The following example creates a solid blue button, featuring a bold white title font. Separators are invisble. 272 | 273 | ```swift 274 | public final class SolidBlueButton: PopupDialogButton { 275 | 276 | override public func setupView() { 277 | defaultFont = UIFont.boldSystemFont(ofSize: 16) 278 | defaultTitleColor = UIColor.white 279 | defaultButtonColor = UIColor.blue 280 | defaultSeparatorColor = UIColor.clear 281 | super.setupView() 282 | } 283 | } 284 | 285 | ``` 286 | 287 | These buttons can be customized with the appearance settings given above as well. 288 | 289 |

 

290 | 291 | ## Dark mode example 292 | 293 | The following is an example of a *Dark Mode* theme. You can find this in the Example project `AppDelegate`, just uncomment it to apply the custom appearance. 294 | 295 | ```swift 296 | // Customize dialog appearance 297 | let pv = PopupDialogDefaultView.appearance() 298 | pv.backgroundColor = UIColor(red:0.23, green:0.23, blue:0.27, alpha:1.00) 299 | pv.titleFont = UIFont(name: "HelveticaNeue-Light", size: 16)! 300 | pv.titleColor = UIColor.white 301 | pv.messageFont = UIFont(name: "HelveticaNeue", size: 14)! 302 | pv.messageColor = UIColor(white: 0.8, alpha: 1) 303 | pv.cornerRadius = 2 304 | 305 | // Customize default button appearance 306 | let db = DefaultButton.appearance() 307 | db.titleFont = UIFont(name: "HelveticaNeue-Medium", size: 14)! 308 | db.titleColor = UIColor.white 309 | db.buttonColor = UIColor(red:0.25, green:0.25, blue:0.29, alpha:1.00) 310 | db.separatorColor = UIColor(red:0.20, green:0.20, blue:0.25, alpha:1.00) 311 | 312 | // Customize cancel button appearance 313 | let cb = CancelButton.appearance() 314 | cb.titleFont = UIFont(name: "HelveticaNeue-Medium", size: 14)! 315 | cb.titleColor = UIColor(white: 0.6, alpha: 1) 316 | cb.buttonColor = UIColor(red:0.25, green:0.25, blue:0.29, alpha:1.00) 317 | cb.separatorColor = UIColor(red:0.20, green:0.20, blue:0.25, alpha:1.00) 318 | 319 | ``` 320 | 321 | 322 | 323 | 324 | I can see that there is room for more customization options. I might add more of them over time. 325 | 326 |

 

327 | 328 | # Screen sizes and rotation 329 | 330 | Rotation and all screen sizes are supported. However, the dialog will never exceed a width of 340 points. This way, the dialog won't be too big on devices like iPads. However, landscape mode will not work well if the height of the dialog exceeds the width of the screen. 331 | 332 |

 

333 | 334 | # Working with text fields 335 | 336 | If you are using text fields in your custom view controller, popup dialog makes sure that the dialog is positioned above the keybord whenever it appears. You can opt out of this behaviour by setting `keyboardShiftsView` to false on a PopupDialog. 337 | 338 | # Testing 339 | 340 | PopupDialog exposes a nice and handy method that lets you trigger a button tap programmatically: 341 | 342 | ```swift 343 | public func tapButtonWithIndex(index: Int) 344 | ``` 345 | 346 | Other than that, PopupDialog unit tests are included in the root folder. 347 | 348 |

 

349 | 350 | # Objective-C 351 | 352 | PopupDialog can be used in Objective-C projects as well. 353 | Here is a basic example: 354 | 355 | ```objective-c 356 | #import 357 | 358 | PopupDialog *popup = [[PopupDialog alloc] initWithTitle:@"TEST" 359 | message:@"This is a test message!" 360 | image:nil 361 | buttonAlignment:UILayoutConstraintAxisHorizontal 362 | transitionStyle:PopupDialogTransitionStyleBounceUp 363 | gestureDismissal:YES 364 | completion:nil]; 365 | 366 | CancelButton *cancel = [[CancelButton alloc] initWithTitle:@"CANCEL" dismissOnTap:YES action:^{ 367 | // Default action 368 | }]; 369 | 370 | DefaultButton *ok = [[DefaultButton alloc] initWithTitle:@"OK" dismissOnTap:YES action:^{ 371 | // Ok action 372 | }]; 373 | 374 | [popup addButtons: @[cancel, ok]]; 375 | 376 | [self presentViewController:popup animated:YES completion:nil]; 377 | ``` 378 | 379 |

 

380 | 381 | # Requirements 382 | 383 | Minimum requirement is iOS 8.0. This dialog was written with Swift 3, for 2.2 compatible versions please specify the X release. 384 | 385 |

 

386 | 387 | # Changelog 388 | 389 | * **0.5.3** Fixed memory leak with custom view controllers 390 | * **0.5.2** Fixed image scaling for default view 391 | * **0.5.1** Introduced custom button height parameter
Reintroduced iOS8 compatibility 392 | * **0.5.0** Swift 3 compatibility / removed iOS8 393 | * **0.4.0** iOS 8 compatibility 394 | * **0.3.3** Fixes buttons being added multiple times 395 | * **0.3.2** Dialog repositioning when interacting with keyboard
Non dismissable buttons option
Additional completion handler when dialog is dismissed 396 | * **0.3.1** Fixed Carthage issues 397 | * **0.3.0** Objective-C compatibility 398 | * **0.2.2** Turned off liveBlur by default to increase performance 399 | * **0.2.1** Dismiss via background tap or swipe down transition 400 | * **0.2.0** You can now pass custom view controllers to the dialog. This introduces breaking changes. 401 | * **0.1.6** Defer button action until animation completes 402 | * **0.1.5** Exposed dialog properties
(titleText, messageText, image, buttonAlignment, transitionStyle) 403 | * **0.1.4** Pick transition animation style 404 | * **0.1.3** Big screen support
Exposed basic shadow appearance 405 | * **0.1.2** Exposed blur and overlay appearance 406 | * **0.1.1** Added themeing example 407 | * **0.1.0** Intitial version 408 | 409 |

 

410 | 411 | # Author 412 | 413 | Martin Wildfeuer, mwfire@mwfire.de 414 | for Orderella Ltd., [orderella.co.uk](http://orderella.co.uk)
415 | You might also want to follow us on Twitter, [@theMWFire](https://twitter.com/theMWFire) | [@Orderella](https://twitter.com/orderella) 416 | 417 | # Thank you 418 | Thanks to everyone who uses, enhances and improves this library, especially the contributors. 419 | 420 |

 

421 | 422 | # Images in the sample project 423 | 424 | The sample project features two images from Markus Spiske raumrot.com:
425 | [Vintage Car One](https://www.pexels.com/photo/lights-vintage-luxury-tires-103290/) | [Vintage Car Two](https://www.pexels.com/photo/lights-car-vintage-luxury-92637/)
426 | Thanks a lot for providing these :) 427 | 428 |

 

429 | 430 | # License 431 | 432 | PopupDialog is available under the MIT license. See the LICENSE file for more info. 433 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## PopupDialog 5 | 6 | Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 7 | Author - Martin Wildfeuer (http://www.mwfire.de) 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | Generated by CocoaPods - https://cocoapods.org 28 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | Copyright (c) 2016 Orderella Ltd. (http://orderella.co.uk) 18 | Author - Martin Wildfeuer (http://www.mwfire.de) 19 | 20 | Permission is hereby granted, free of charge, to any person obtaining a copy 21 | of this software and associated documentation files (the "Software"), to deal 22 | in the Software without restriction, including without limitation the rights 23 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | copies of the Software, and to permit persons to whom the Software is 25 | furnished to do so, subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in 28 | all copies or substantial portions of the Software. 29 | 30 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | THE SOFTWARE. 37 | 38 | License 39 | MIT 40 | Title 41 | PopupDialog 42 | Type 43 | PSGroupSpecifier 44 | 45 | 46 | FooterText 47 | Generated by CocoaPods - https://cocoapods.org 48 | Title 49 | 50 | Type 51 | PSGroupSpecifier 52 | 53 | 54 | StringsTable 55 | Acknowledgements 56 | Title 57 | Acknowledgements 58 | 59 | 60 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_PopupDialogTableView : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_PopupDialogTableView 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\"" 63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1" 64 | fi 65 | } 66 | 67 | # Strip invalid architectures 68 | strip_invalid_archs() { 69 | binary="$1" 70 | # Get architectures for current file 71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 72 | stripped="" 73 | for arch in $archs; do 74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 75 | # Strip non-valid architectures in-place 76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 77 | stripped="$stripped $arch" 78 | fi 79 | done 80 | if [[ "$stripped" ]]; then 81 | echo "Stripped $binary of architectures:$stripped" 82 | fi 83 | } 84 | 85 | 86 | if [[ "$CONFIGURATION" == "Debug" ]]; then 87 | install_framework "$BUILT_PRODUCTS_DIR/PopupDialog/PopupDialog.framework" 88 | fi 89 | if [[ "$CONFIGURATION" == "Release" ]]; then 90 | install_framework "$BUILT_PRODUCTS_DIR/PopupDialog/PopupDialog.framework" 91 | fi 92 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | case "${TARGETED_DEVICE_FAMILY}" in 12 | 1,2) 13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 14 | ;; 15 | 1) 16 | TARGET_DEVICE_ARGS="--target-device iphone" 17 | ;; 18 | 2) 19 | TARGET_DEVICE_ARGS="--target-device ipad" 20 | ;; 21 | *) 22 | TARGET_DEVICE_ARGS="--target-device mac" 23 | ;; 24 | esac 25 | 26 | install_resource() 27 | { 28 | if [[ "$1" = /* ]] ; then 29 | RESOURCE_PATH="$1" 30 | else 31 | RESOURCE_PATH="${PODS_ROOT}/$1" 32 | fi 33 | if [[ ! -e "$RESOURCE_PATH" ]] ; then 34 | cat << EOM 35 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script. 36 | EOM 37 | exit 1 38 | fi 39 | case $RESOURCE_PATH in 40 | *.storyboard) 41 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 42 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 43 | ;; 44 | *.xib) 45 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" 46 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS} 47 | ;; 48 | *.framework) 49 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 50 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 51 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 52 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 53 | ;; 54 | *.xcdatamodel) 55 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" 56 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom" 57 | ;; 58 | *.xcdatamodeld) 59 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" 60 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd" 61 | ;; 62 | *.xcmappingmodel) 63 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" 64 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm" 65 | ;; 66 | *.xcassets) 67 | ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH" 68 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 69 | ;; 70 | *) 71 | echo "$RESOURCE_PATH" 72 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY" 73 | ;; 74 | esac 75 | } 76 | 77 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 78 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 79 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 80 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 81 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 82 | fi 83 | rm -f "$RESOURCES_TO_COPY" 84 | 85 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 86 | then 87 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 88 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 89 | while read line; do 90 | if [[ $line != "${PODS_ROOT}*" ]]; then 91 | XCASSET_FILES+=("$line") 92 | fi 93 | done <<<"$OTHER_XCASSETS" 94 | 95 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 96 | fi 97 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | 6 | FOUNDATION_EXPORT double Pods_PopupDialogTableViewVersionNumber; 7 | FOUNDATION_EXPORT const unsigned char Pods_PopupDialogTableViewVersionString[]; 8 | 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/PopupDialog" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/PopupDialog/PopupDialog.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "PopupDialog" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = $BUILD_DIR 10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_PopupDialogTableView { 2 | umbrella header "Pods-PopupDialogTableView-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/PopupDialog" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/PopupDialog/PopupDialog.framework/Headers" 7 | OTHER_LDFLAGS = $(inherited) -framework "PopupDialog" 8 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 9 | PODS_BUILD_DIR = $BUILD_DIR 10 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.5.3 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/PopupDialog-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_PopupDialog : NSObject 3 | @end 4 | @implementation PodsDummy_PopupDialog 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/PopupDialog-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/PopupDialog-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | #import "FXBlurView.h" 6 | 7 | FOUNDATION_EXPORT double PopupDialogVersionNumber; 8 | FOUNDATION_EXPORT const unsigned char PopupDialogVersionString[]; 9 | 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/PopupDialog.modulemap: -------------------------------------------------------------------------------- 1 | framework module PopupDialog { 2 | umbrella header "PopupDialog-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/PopupDialog/PopupDialog.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PopupDialog 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public" 4 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 5 | PODS_BUILD_DIR = $BUILD_DIR 6 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_ROOT = ${SRCROOT} 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /PopupDialogTableView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 3B57A3FFCAEB4DA80E099DA0 /* Pods_PopupDialogTableView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2EA7A1D44A54F85B4B4B629E /* Pods_PopupDialogTableView.framework */; }; 11 | C7C699F31E1800E80040CF29 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C699F21E1800E80040CF29 /* AppDelegate.swift */; }; 12 | C7C699F51E1800E80040CF29 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C699F41E1800E80040CF29 /* ViewController.swift */; }; 13 | C7C699F81E1800E80040CF29 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7C699F61E1800E80040CF29 /* Main.storyboard */; }; 14 | C7C699FA1E1800E80040CF29 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C7C699F91E1800E80040CF29 /* Assets.xcassets */; }; 15 | C7C699FD1E1800E80040CF29 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C7C699FB1E1800E80040CF29 /* LaunchScreen.storyboard */; }; 16 | C7C69A051E1803A10040CF29 /* PopupTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C69A041E1803A10040CF29 /* PopupTableView.swift */; }; 17 | C7C69A071E1806790040CF29 /* PopupTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C69A061E1806790040CF29 /* PopupTableViewController.swift */; }; 18 | C7C69A091E180B560040CF29 /* PopupTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7C69A081E180B560040CF29 /* PopupTableViewCell.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 2EA7A1D44A54F85B4B4B629E /* Pods_PopupDialogTableView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PopupDialogTableView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | A153E064EE710C60BE20EF93 /* Pods-PopupDialogTableView.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PopupDialogTableView.debug.xcconfig"; path = "Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView.debug.xcconfig"; sourceTree = ""; }; 24 | A4D40C0AF78D9849CDE1093A /* Pods-PopupDialogTableView.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PopupDialogTableView.release.xcconfig"; path = "Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView.release.xcconfig"; sourceTree = ""; }; 25 | C7C699EF1E1800E80040CF29 /* PopupDialogTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PopupDialogTableView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | C7C699F21E1800E80040CF29 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 27 | C7C699F41E1800E80040CF29 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 28 | C7C699F71E1800E80040CF29 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 29 | C7C699F91E1800E80040CF29 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 30 | C7C699FC1E1800E80040CF29 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 31 | C7C699FE1E1800E80040CF29 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 32 | C7C69A041E1803A10040CF29 /* PopupTableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopupTableView.swift; sourceTree = ""; }; 33 | C7C69A061E1806790040CF29 /* PopupTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopupTableViewController.swift; sourceTree = ""; }; 34 | C7C69A081E180B560040CF29 /* PopupTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopupTableViewCell.swift; sourceTree = ""; }; 35 | /* End PBXFileReference section */ 36 | 37 | /* Begin PBXFrameworksBuildPhase section */ 38 | C7C699EC1E1800E80040CF29 /* Frameworks */ = { 39 | isa = PBXFrameworksBuildPhase; 40 | buildActionMask = 2147483647; 41 | files = ( 42 | 3B57A3FFCAEB4DA80E099DA0 /* Pods_PopupDialogTableView.framework in Frameworks */, 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 44488E9C909AC0BB1DE7F0F8 /* Frameworks */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | 2EA7A1D44A54F85B4B4B629E /* Pods_PopupDialogTableView.framework */, 53 | ); 54 | name = Frameworks; 55 | sourceTree = ""; 56 | }; 57 | A461A60FEC40F5B918BADAC9 /* Pods */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | A153E064EE710C60BE20EF93 /* Pods-PopupDialogTableView.debug.xcconfig */, 61 | A4D40C0AF78D9849CDE1093A /* Pods-PopupDialogTableView.release.xcconfig */, 62 | ); 63 | name = Pods; 64 | sourceTree = ""; 65 | }; 66 | C7C699E61E1800E80040CF29 = { 67 | isa = PBXGroup; 68 | children = ( 69 | C7C699F11E1800E80040CF29 /* PopupDialogTableView */, 70 | C7C699F01E1800E80040CF29 /* Products */, 71 | A461A60FEC40F5B918BADAC9 /* Pods */, 72 | 44488E9C909AC0BB1DE7F0F8 /* Frameworks */, 73 | ); 74 | sourceTree = ""; 75 | }; 76 | C7C699F01E1800E80040CF29 /* Products */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | C7C699EF1E1800E80040CF29 /* PopupDialogTableView.app */, 80 | ); 81 | name = Products; 82 | sourceTree = ""; 83 | }; 84 | C7C699F11E1800E80040CF29 /* PopupDialogTableView */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | C7C699F21E1800E80040CF29 /* AppDelegate.swift */, 88 | C7C699F41E1800E80040CF29 /* ViewController.swift */, 89 | C7C699F61E1800E80040CF29 /* Main.storyboard */, 90 | C7C699F91E1800E80040CF29 /* Assets.xcassets */, 91 | C7C699FB1E1800E80040CF29 /* LaunchScreen.storyboard */, 92 | C7C699FE1E1800E80040CF29 /* Info.plist */, 93 | C7C69A041E1803A10040CF29 /* PopupTableView.swift */, 94 | C7C69A061E1806790040CF29 /* PopupTableViewController.swift */, 95 | C7C69A081E180B560040CF29 /* PopupTableViewCell.swift */, 96 | ); 97 | path = PopupDialogTableView; 98 | sourceTree = ""; 99 | }; 100 | /* End PBXGroup section */ 101 | 102 | /* Begin PBXNativeTarget section */ 103 | C7C699EE1E1800E80040CF29 /* PopupDialogTableView */ = { 104 | isa = PBXNativeTarget; 105 | buildConfigurationList = C7C69A011E1800E80040CF29 /* Build configuration list for PBXNativeTarget "PopupDialogTableView" */; 106 | buildPhases = ( 107 | B77B679D84CA48309B160B60 /* [CP] Check Pods Manifest.lock */, 108 | C7C699EB1E1800E80040CF29 /* Sources */, 109 | C7C699EC1E1800E80040CF29 /* Frameworks */, 110 | C7C699ED1E1800E80040CF29 /* Resources */, 111 | 31EEEE7F47B256D6C1367890 /* [CP] Embed Pods Frameworks */, 112 | 3595D6E8F012D9B31A22775E /* [CP] Copy Pods Resources */, 113 | ); 114 | buildRules = ( 115 | ); 116 | dependencies = ( 117 | ); 118 | name = PopupDialogTableView; 119 | productName = PopupDialogTableView; 120 | productReference = C7C699EF1E1800E80040CF29 /* PopupDialogTableView.app */; 121 | productType = "com.apple.product-type.application"; 122 | }; 123 | /* End PBXNativeTarget section */ 124 | 125 | /* Begin PBXProject section */ 126 | C7C699E71E1800E80040CF29 /* Project object */ = { 127 | isa = PBXProject; 128 | attributes = { 129 | LastSwiftUpdateCheck = 0820; 130 | LastUpgradeCheck = 0820; 131 | ORGANIZATIONNAME = "mwfire development"; 132 | TargetAttributes = { 133 | C7C699EE1E1800E80040CF29 = { 134 | CreatedOnToolsVersion = 8.2.1; 135 | DevelopmentTeam = Q249KDW6P6; 136 | ProvisioningStyle = Automatic; 137 | }; 138 | }; 139 | }; 140 | buildConfigurationList = C7C699EA1E1800E80040CF29 /* Build configuration list for PBXProject "PopupDialogTableView" */; 141 | compatibilityVersion = "Xcode 3.2"; 142 | developmentRegion = English; 143 | hasScannedForEncodings = 0; 144 | knownRegions = ( 145 | en, 146 | Base, 147 | ); 148 | mainGroup = C7C699E61E1800E80040CF29; 149 | productRefGroup = C7C699F01E1800E80040CF29 /* Products */; 150 | projectDirPath = ""; 151 | projectRoot = ""; 152 | targets = ( 153 | C7C699EE1E1800E80040CF29 /* PopupDialogTableView */, 154 | ); 155 | }; 156 | /* End PBXProject section */ 157 | 158 | /* Begin PBXResourcesBuildPhase section */ 159 | C7C699ED1E1800E80040CF29 /* Resources */ = { 160 | isa = PBXResourcesBuildPhase; 161 | buildActionMask = 2147483647; 162 | files = ( 163 | C7C699FD1E1800E80040CF29 /* LaunchScreen.storyboard in Resources */, 164 | C7C699FA1E1800E80040CF29 /* Assets.xcassets in Resources */, 165 | C7C699F81E1800E80040CF29 /* Main.storyboard in Resources */, 166 | ); 167 | runOnlyForDeploymentPostprocessing = 0; 168 | }; 169 | /* End PBXResourcesBuildPhase section */ 170 | 171 | /* Begin PBXShellScriptBuildPhase section */ 172 | 31EEEE7F47B256D6C1367890 /* [CP] Embed Pods Frameworks */ = { 173 | isa = PBXShellScriptBuildPhase; 174 | buildActionMask = 2147483647; 175 | files = ( 176 | ); 177 | inputPaths = ( 178 | ); 179 | name = "[CP] Embed Pods Frameworks"; 180 | outputPaths = ( 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-frameworks.sh\"\n"; 185 | showEnvVarsInLog = 0; 186 | }; 187 | 3595D6E8F012D9B31A22775E /* [CP] Copy Pods Resources */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | ); 192 | inputPaths = ( 193 | ); 194 | name = "[CP] Copy Pods Resources"; 195 | outputPaths = ( 196 | ); 197 | runOnlyForDeploymentPostprocessing = 0; 198 | shellPath = /bin/sh; 199 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-PopupDialogTableView/Pods-PopupDialogTableView-resources.sh\"\n"; 200 | showEnvVarsInLog = 0; 201 | }; 202 | B77B679D84CA48309B160B60 /* [CP] Check Pods Manifest.lock */ = { 203 | isa = PBXShellScriptBuildPhase; 204 | buildActionMask = 2147483647; 205 | files = ( 206 | ); 207 | inputPaths = ( 208 | ); 209 | name = "[CP] Check Pods Manifest.lock"; 210 | outputPaths = ( 211 | ); 212 | runOnlyForDeploymentPostprocessing = 0; 213 | shellPath = /bin/sh; 214 | shellScript = "diff \"${PODS_ROOT}/../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"; 215 | showEnvVarsInLog = 0; 216 | }; 217 | /* End PBXShellScriptBuildPhase section */ 218 | 219 | /* Begin PBXSourcesBuildPhase section */ 220 | C7C699EB1E1800E80040CF29 /* Sources */ = { 221 | isa = PBXSourcesBuildPhase; 222 | buildActionMask = 2147483647; 223 | files = ( 224 | C7C69A071E1806790040CF29 /* PopupTableViewController.swift in Sources */, 225 | C7C69A091E180B560040CF29 /* PopupTableViewCell.swift in Sources */, 226 | C7C69A051E1803A10040CF29 /* PopupTableView.swift in Sources */, 227 | C7C699F51E1800E80040CF29 /* ViewController.swift in Sources */, 228 | C7C699F31E1800E80040CF29 /* AppDelegate.swift in Sources */, 229 | ); 230 | runOnlyForDeploymentPostprocessing = 0; 231 | }; 232 | /* End PBXSourcesBuildPhase section */ 233 | 234 | /* Begin PBXVariantGroup section */ 235 | C7C699F61E1800E80040CF29 /* Main.storyboard */ = { 236 | isa = PBXVariantGroup; 237 | children = ( 238 | C7C699F71E1800E80040CF29 /* Base */, 239 | ); 240 | name = Main.storyboard; 241 | sourceTree = ""; 242 | }; 243 | C7C699FB1E1800E80040CF29 /* LaunchScreen.storyboard */ = { 244 | isa = PBXVariantGroup; 245 | children = ( 246 | C7C699FC1E1800E80040CF29 /* Base */, 247 | ); 248 | name = LaunchScreen.storyboard; 249 | sourceTree = ""; 250 | }; 251 | /* End PBXVariantGroup section */ 252 | 253 | /* Begin XCBuildConfiguration section */ 254 | C7C699FF1E1800E80040CF29 /* Debug */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_ANALYZER_NONNULL = YES; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 267 | CLANG_WARN_EMPTY_BODY = YES; 268 | CLANG_WARN_ENUM_CONVERSION = YES; 269 | CLANG_WARN_INFINITE_RECURSION = YES; 270 | CLANG_WARN_INT_CONVERSION = YES; 271 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 272 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 273 | CLANG_WARN_UNREACHABLE_CODE = YES; 274 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 275 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 276 | COPY_PHASE_STRIP = NO; 277 | DEBUG_INFORMATION_FORMAT = dwarf; 278 | ENABLE_STRICT_OBJC_MSGSEND = YES; 279 | ENABLE_TESTABILITY = YES; 280 | GCC_C_LANGUAGE_STANDARD = gnu99; 281 | GCC_DYNAMIC_NO_PIC = NO; 282 | GCC_NO_COMMON_BLOCKS = YES; 283 | GCC_OPTIMIZATION_LEVEL = 0; 284 | GCC_PREPROCESSOR_DEFINITIONS = ( 285 | "DEBUG=1", 286 | "$(inherited)", 287 | ); 288 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 289 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 290 | GCC_WARN_UNDECLARED_SELECTOR = YES; 291 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 292 | GCC_WARN_UNUSED_FUNCTION = YES; 293 | GCC_WARN_UNUSED_VARIABLE = YES; 294 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 295 | MTL_ENABLE_DEBUG_INFO = YES; 296 | ONLY_ACTIVE_ARCH = YES; 297 | SDKROOT = iphoneos; 298 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 299 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 300 | }; 301 | name = Debug; 302 | }; 303 | C7C69A001E1800E80040CF29 /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ALWAYS_SEARCH_USER_PATHS = NO; 307 | CLANG_ANALYZER_NONNULL = YES; 308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 309 | CLANG_CXX_LIBRARY = "libc++"; 310 | CLANG_ENABLE_MODULES = YES; 311 | CLANG_ENABLE_OBJC_ARC = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 316 | CLANG_WARN_EMPTY_BODY = YES; 317 | CLANG_WARN_ENUM_CONVERSION = YES; 318 | CLANG_WARN_INFINITE_RECURSION = YES; 319 | CLANG_WARN_INT_CONVERSION = YES; 320 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 321 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 322 | CLANG_WARN_UNREACHABLE_CODE = YES; 323 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 324 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 325 | COPY_PHASE_STRIP = NO; 326 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 327 | ENABLE_NS_ASSERTIONS = NO; 328 | ENABLE_STRICT_OBJC_MSGSEND = YES; 329 | GCC_C_LANGUAGE_STANDARD = gnu99; 330 | GCC_NO_COMMON_BLOCKS = YES; 331 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 332 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 333 | GCC_WARN_UNDECLARED_SELECTOR = YES; 334 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 335 | GCC_WARN_UNUSED_FUNCTION = YES; 336 | GCC_WARN_UNUSED_VARIABLE = YES; 337 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 338 | MTL_ENABLE_DEBUG_INFO = NO; 339 | SDKROOT = iphoneos; 340 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 341 | VALIDATE_PRODUCT = YES; 342 | }; 343 | name = Release; 344 | }; 345 | C7C69A021E1800E80040CF29 /* Debug */ = { 346 | isa = XCBuildConfiguration; 347 | baseConfigurationReference = A153E064EE710C60BE20EF93 /* Pods-PopupDialogTableView.debug.xcconfig */; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | DEVELOPMENT_TEAM = Q249KDW6P6; 351 | INFOPLIST_FILE = PopupDialogTableView/Info.plist; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = de.mwfire.PopupDialogTableView; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | SWIFT_VERSION = 3.0; 356 | }; 357 | name = Debug; 358 | }; 359 | C7C69A031E1800E80040CF29 /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | baseConfigurationReference = A4D40C0AF78D9849CDE1093A /* Pods-PopupDialogTableView.release.xcconfig */; 362 | buildSettings = { 363 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 364 | DEVELOPMENT_TEAM = Q249KDW6P6; 365 | INFOPLIST_FILE = PopupDialogTableView/Info.plist; 366 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 367 | PRODUCT_BUNDLE_IDENTIFIER = de.mwfire.PopupDialogTableView; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | SWIFT_VERSION = 3.0; 370 | }; 371 | name = Release; 372 | }; 373 | /* End XCBuildConfiguration section */ 374 | 375 | /* Begin XCConfigurationList section */ 376 | C7C699EA1E1800E80040CF29 /* Build configuration list for PBXProject "PopupDialogTableView" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | C7C699FF1E1800E80040CF29 /* Debug */, 380 | C7C69A001E1800E80040CF29 /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | C7C69A011E1800E80040CF29 /* Build configuration list for PBXNativeTarget "PopupDialogTableView" */ = { 386 | isa = XCConfigurationList; 387 | buildConfigurations = ( 388 | C7C69A021E1800E80040CF29 /* Debug */, 389 | C7C69A031E1800E80040CF29 /* Release */, 390 | ); 391 | defaultConfigurationIsVisible = 0; 392 | defaultConfigurationName = Release; 393 | }; 394 | /* End XCConfigurationList section */ 395 | }; 396 | rootObject = C7C699E71E1800E80040CF29 /* Project object */; 397 | } 398 | -------------------------------------------------------------------------------- /PopupDialogTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PopupDialogTableView.xcodeproj/xcuserdata/mwfire.xcuserdatad/xcschemes/PopupDialogTableView.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 | -------------------------------------------------------------------------------- /PopupDialogTableView.xcodeproj/xcuserdata/mwfire.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | PopupDialogTableView.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C7C699EE1E1800E80040CF29 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /PopupDialogTableView.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /PopupDialogTableView/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // PopupDialogTableView 4 | // 5 | // Created by Martin Wildfeuer on 31.12.16. 6 | // Copyright © 2016 mwfire development. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /PopupDialogTableView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /PopupDialogTableView/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 | -------------------------------------------------------------------------------- /PopupDialogTableView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /PopupDialogTableView/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 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /PopupDialogTableView/PopupTableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupTableView.swift 3 | // PopupDialogTableView 4 | // 5 | // Created by Martin Wildfeuer on 31.12.16. 6 | // Copyright © 2016 mwfire development. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PopupTableView: UIView { 12 | 13 | // The title label 14 | lazy var titleLabel: UILabel = { 15 | let label = UILabel(frame: .zero) 16 | label.translatesAutoresizingMaskIntoConstraints = false 17 | label.textColor = UIColor(red: 0.25, green: 0.53, blue: 0.91, alpha: 1) 18 | label.textAlignment = .center 19 | return label 20 | }() 21 | 22 | // The table view 23 | lazy var tableView: UITableView = { 24 | let tv = UITableView(frame: .zero) 25 | tv.translatesAutoresizingMaskIntoConstraints = false 26 | return tv 27 | }() 28 | 29 | override func didMoveToSuperview() { 30 | super.didMoveToSuperview() 31 | 32 | // Add views 33 | addSubview(titleLabel) 34 | addSubview(tableView) 35 | 36 | // Setup constraints 37 | heightAnchor.constraint(equalToConstant: 220).isActive = true 38 | 39 | var constraints = [NSLayoutConstraint]() 40 | let views: [String: UIView] = ["titleLabel": titleLabel, "tableView": tableView] 41 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[tableView]|", options: [], metrics: nil, views: views) 42 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "V:|[titleLabel(50)][tableView]|", options: [], metrics: nil, views: views) 43 | constraints += NSLayoutConstraint.constraints(withVisualFormat: "H:|[titleLabel]|", options: [], metrics: nil, views: views) 44 | NSLayoutConstraint.activate(constraints) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PopupDialogTableView/PopupTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupTableViewCell.swift 3 | // PopupDialogTableView 4 | // 5 | // Created by Martin Wildfeuer on 31.12.16. 6 | // Copyright © 2016 mwfire development. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class PopupTableViewCell: UITableViewCell { 12 | 13 | /// The reuse identifier for this cell 14 | static let cellIdentifier = "PopupTableViewCell" 15 | 16 | override func awakeFromNib() { 17 | super.awakeFromNib() 18 | // Initialization code 19 | } 20 | 21 | override func setSelected(_ selected: Bool, animated: Bool) { 22 | super.setSelected(false, animated: animated) 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /PopupDialogTableView/PopupTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PopupTableViewController.swift 3 | // PopupDialogTableView 4 | // 5 | // Created by Martin Wildfeuer on 31.12.16. 6 | // Copyright © 2016 mwfire development. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import PopupDialog 11 | 12 | final class PopupTableViewController: UIViewController { 13 | 14 | // MARK: Public 15 | 16 | /// The PopupDialog this view is contained in 17 | /// Note: this has to be weak, otherwise we end up 18 | /// creating a retain cycle! 19 | public weak var popup: PopupDialog? 20 | 21 | /// The city the user did choose 22 | public fileprivate(set) var selectedCity: String? 23 | 24 | /// A list of cities to display 25 | public var cities = [String]() { 26 | didSet { baseView.tableView.reloadData() } 27 | } 28 | 29 | // MARK: Private 30 | 31 | // We will use this instead to reference our 32 | // controllers view instead of `view` 33 | fileprivate var baseView: PopupTableView { 34 | return view as! PopupTableView 35 | } 36 | 37 | // MARK: View related 38 | 39 | // Replace the original controller view 40 | // with our dedicated view 41 | override func loadView() { 42 | view = PopupTableView(frame: .zero) 43 | } 44 | 45 | override func viewDidLoad() { 46 | super.viewDidLoad() 47 | 48 | // Set the dialog (custom) title 49 | baseView.titleLabel.text = "Choose City" 50 | 51 | // Setup tableView 52 | baseView.tableView.register(PopupTableViewCell.self, forCellReuseIdentifier: PopupTableViewCell.cellIdentifier) 53 | baseView.tableView.dataSource = self 54 | baseView.tableView.delegate = self 55 | } 56 | } 57 | 58 | // MARK: - TableView Data Source 59 | 60 | extension PopupTableViewController: UITableViewDataSource { 61 | 62 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 63 | return cities.count 64 | } 65 | 66 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 67 | let cell = tableView.dequeueReusableCell(withIdentifier: PopupTableViewCell.cellIdentifier, for: indexPath) 68 | cell.textLabel?.text = cities[indexPath.row] 69 | return cell 70 | } 71 | } 72 | 73 | // MARK: - TableView Delegate 74 | 75 | extension PopupTableViewController: UITableViewDelegate { 76 | 77 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 78 | selectedCity = cities[indexPath.row] 79 | popup?.dismiss(animated: true) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /PopupDialogTableView/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // PopupDialogTableView 4 | // 5 | // Created by Martin Wildfeuer on 31.12.16. 6 | // Copyright © 2016 mwfire development. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import PopupDialog 11 | 12 | class ViewController: UIViewController { 13 | 14 | // Called whenever the storyboard button is tapped 15 | @IBAction func onSelectCityTapped(_ sender: UIButton) { 16 | 17 | // Create our custom view controller programatically 18 | let vc = PopupTableViewController(nibName: nil, bundle: nil) 19 | 20 | // Create the PopupDialog with a completion handler, 21 | // called whenever the dialog is dismissed 22 | let popup = PopupDialog(viewController: vc, gestureDismissal: false) { 23 | guard let city = vc.selectedCity else { return } 24 | print("User selected city: \(city)") 25 | } 26 | 27 | // Create a cancel button for the dialog, 28 | // including a button action 29 | let cancel = DefaultButton(title: "Cancel") { 30 | print("User did not select a city") 31 | } 32 | 33 | // Add the cancel button we just created to the dialog 34 | popup.addButton(cancel) 35 | 36 | // Moreover, we set a list of cities on our custom view controller 37 | vc.cities = ["Munich", "Budapest", "Krakow", "Rome", "Paris", "Nice", "Madrid", "New York", "Moscow", "Peking", "Tokyo"] 38 | 39 | // We also pass a reference to our PopupDialog to our custom view controller 40 | // This way, we can dismiss and manipulate it from there 41 | vc.popup = popup 42 | 43 | // Last but not least: present the PopupDialog 44 | present(popup, animated: true, completion: nil) 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Popup Dialog City Picker Example 2 | 3 | This is a basic example of using a custom view controller with [Popup Dialog](https://github.com/Orderella/PopupDialog). This view controller is created programatically, so there is no xib involved. It contains a custom title label and a table view controller, used as a city picker. 4 | 5 | 6 | 7 | ## How to 8 | 9 | Just clone this repo and have a look at the classes, I have commented the steps needed to create the city picker. Find below the code to create the dialog, it can be found in `ViewController.swift`. 10 | 11 | ```swift 12 | // Create our custom view controller programatically 13 | let vc = PopupTableViewController(nibName: nil, bundle: nil) 14 | 15 | // Create the PopupDialog with a completion handler, 16 | // called whenever the dialog is dismissed 17 | let popup = PopupDialog(viewController: vc, gestureDismissal: false) { 18 | guard let city = vc.selectedCity else { return } 19 | print("User selected city: \(city)") 20 | } 21 | 22 | // Create a cancel button for the dialog, 23 | // including a button action 24 | let cancel = DefaultButton(title: "Cancel") { 25 | print("User did not select a city") 26 | } 27 | 28 | // Add the cancel button we just created to the dialog 29 | popup.addButton(cancel) 30 | 31 | // Moreover, we set a list of cities on our custom view controller 32 | vc.cities = ["Munich", "Budapest", "Krakow", "Rome", "Paris", "Nice", "Madrid", "New York", "Moscow", "Peking", "Tokyo"] 33 | 34 | // We also pass a reference to our PopupDialog to our custom view controller 35 | // This way, we can dismiss and manipulate it from there 36 | vc.popup = popup 37 | 38 | // Last but not least: present the PopupDialog 39 | present(popup, animated: true, completion: nil) 40 | ``` 41 | 42 | ## Author 43 | 44 | Martin Wildfeuer, mwfire@mwfire.de 45 | You might also want to follow me on Twitter, [@theMWFire](https://twitter.com/theMWFire) 46 | 47 | ## License 48 | 49 | PopupDialogTableView is available under the MIT license. See the LICENSE file for more info. --------------------------------------------------------------------------------