├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── AlertController.podspec.json ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── AlertController │ └── AlertController.swift └── Tests └── AlertControllerTests └── AlertControllerTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AlertController.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AlertController", 3 | "version": "0.0.3", 4 | "summary": "💬 A tiny extension for UIAlertController that makes working with it very simple", 5 | "homepage": "https://github.com/mezhevikin/AlertController", 6 | "license": { 7 | "type": "MIT", 8 | "file": "LICENSE" 9 | }, 10 | "authors": { 11 | "Mezhevikin Alexey": "mezhevikin@gmail.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/mezhevikin/AlertController.git", 15 | "tag": "0.0.3" 16 | }, 17 | "platforms": { 18 | "ios": "13.0" 19 | }, 20 | "source_files": "Sources/**/*", 21 | "pushed_with_swift_version": "5.5", 22 | "frameworks": [ 23 | "UIKit" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2022 Mezhevikin Alexey 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.5 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "AlertController", 6 | platforms: [ 7 | .iOS(.v13) 8 | ], 9 | products: [ 10 | .library( 11 | name: "AlertController", 12 | targets: ["AlertController"]), 13 | ], 14 | dependencies: [ 15 | 16 | ], 17 | targets: [ 18 | .target( 19 | name: "AlertController", 20 | dependencies: [] 21 | ), 22 | .testTarget( 23 | name: "AlertControllerTests", 24 | dependencies: ["AlertController"]), 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AlertController 2 | 3 | 💬 A tiny extension for UIAlertController that makes working with it very simple. Only 150 lines of code. 4 | 5 | ### Alert 6 | 7 | ```swift 8 | let alert = UIAlertController.alert() 9 | alert.setTitle("✅ Success", color: .darkGreen) 10 | alert.setMessage("Your message has been sent") 11 | alert.addAction( 12 | title: "Send more", 13 | systemIcon: "envelope.fill", 14 | color: .darkGreen, 15 | leftAligment: true 16 | ) {} 17 | alert.addAction( 18 | title: "Delete message", 19 | systemIcon: "trash.fill", 20 | color: .red, 21 | leftAligment: true 22 | ) {} 23 | alert.addOkAction() 24 | present(alert, animated: true) 25 | ``` 26 | 27 |

28 | 29 |

30 | 31 | ### Sheet 32 | 33 | ```swift 34 | let sheet = UIAlertController.sheet("👨🏻 Mezhevikin Alexey") 35 | sheet.addAction( 36 | title: "Edit profile", 37 | systemIcon: "person.fill", 38 | color: .darkGreen, 39 | leftAligment: true 40 | ) {} 41 | sheet.addAction( 42 | title: "Delete account", 43 | systemIcon: "trash.fill", 44 | color: .red, 45 | leftAligment: true 46 | ) {} 47 | sheet.addAction( 48 | title: "Log out", 49 | systemIcon: "square.and.arrow.down.fill", 50 | leftAligment: true 51 | ) {} 52 | sheet.addCancelAction() 53 | present(sheet, sourceView: cell) 54 | ``` 55 | 56 |

57 | 58 |

59 | 60 | ### Choice 61 | 62 | ```swift 63 | let sheet = UIAlertController.sheet("Choose your favorite animal") 64 | let animals = ["🐈 Cat", "🐕 Dog", "🐎 Horse", "🐫 Camel"] 65 | for (i, animal) in animals.enumerated() { 66 | sheet.addAction( 67 | title: animal, 68 | checked: favoriteAnimal == i, 69 | leftAligment: true 70 | ) { 71 | self.favoriteAnimal = i 72 | } 73 | } 74 | sheet.addCancelAction() 75 | present(sheet, sourceView: cell) 76 | ``` 77 | 78 |

79 | 80 |

81 | 82 | ### TextField 83 | 84 | ```swift 85 | let alert = UIAlertController.alert("🔓 Login") 86 | alert.addTextField { 87 | $0.placeholder = "✉️ Mail" 88 | } 89 | alert.addTextField { 90 | $0.placeholder = "🔑 Password" 91 | $0.isSecureTextEntry = true 92 | } 93 | alert.addAction(title: "OK") { 94 | if let mail = alert.textFields?[0].text, 95 | let password = alert.textFields?[1].text 96 | { 97 | print("✉️ \(mail), 🔑 \(password)") 98 | } 99 | } 100 | present(alert) 101 | ``` 102 | 103 |

104 | 105 |

106 | 107 | ### Present 108 | 109 | ```swift 110 | // Alert 111 | present(alert) 112 | // Sheet from cell with iPad support 113 | present(sheet, sourceView: cell) 114 | // Sheet from BarButton with iPad support 115 | present(sheet, barButtonItem: navigationItem.leftBarButtonItem) 116 | ``` 117 | 118 | ### Swift Package Manager 119 | 120 | ``` 121 | https://github.com/mezhevikin/AlertController.git 122 | ``` 123 | 124 | ### CocoaPods 125 | 126 | ``` 127 | pod 'AlertController', :git => 'https://github.com/mezhevikin/AlertController.git' 128 | ``` -------------------------------------------------------------------------------- /Sources/AlertController/AlertController.swift: -------------------------------------------------------------------------------- 1 | // Mezhevikin Alexey: https://github.com/mezhevikin/AlertController 2 | import UIKit 3 | 4 | public extension UIAlertController { 5 | static func alert( 6 | _ title: String? = nil, 7 | message: String? = nil 8 | ) -> UIAlertController { 9 | UIAlertController( 10 | title: title, 11 | message: message, 12 | preferredStyle: .alert 13 | ) 14 | } 15 | 16 | static func sheet( 17 | _ title: String? = nil 18 | ) -> UIAlertController { 19 | let sheet = UIAlertController( 20 | title: nil, 21 | message: nil, 22 | preferredStyle: .actionSheet 23 | ) 24 | if let title = title { 25 | sheet.addAction(title: title, enabled: false) 26 | } 27 | return sheet 28 | } 29 | 30 | @discardableResult 31 | func addAction( 32 | title: String, 33 | style: UIAlertAction.Style = .default, 34 | icon: String? = nil, 35 | systemIcon: String? = nil, 36 | color: UIColor? = nil, 37 | enabled: Bool = true, 38 | checked: Bool = false, 39 | leftAligment: Bool = false, 40 | handler: (() -> Void)? = nil 41 | ) -> UIAlertAction { 42 | let action = UIAlertAction(title: title, style: style) { _ in 43 | if let handler = handler { handler() } 44 | } 45 | if let icon = icon { 46 | action.setIcon(icon) 47 | } 48 | if let systemIcon = systemIcon { 49 | action.setIcon(systemIcon, isSystem: true) 50 | } 51 | if let color = color { 52 | action.setColor(color) 53 | } 54 | action.isEnabled = enabled 55 | action.setChecked(checked) 56 | action.setLeftAligment(leftAligment) 57 | addAction(action) 58 | return action 59 | } 60 | 61 | func addCancelAction() { 62 | addAction( 63 | title: NSLocalizedString("Cancel", comment: ""), 64 | style: .cancel 65 | ) 66 | } 67 | 68 | func addOkAction() { 69 | addAction( 70 | title: NSLocalizedString("OK", comment: ""), 71 | style: .cancel 72 | ) 73 | } 74 | 75 | func setTitle( 76 | _ title: String, 77 | color: UIColor = .label, 78 | size: CGFloat = 20 79 | ) { 80 | setValue(NSAttributedString(string: title, attributes: [ 81 | .font: UIFont.systemFont(ofSize: size), 82 | .foregroundColor: color 83 | ]), forKey: "attributedTitle") 84 | } 85 | 86 | func setMessage( 87 | _ message: String, 88 | color: UIColor = .secondaryLabel, 89 | size: CGFloat = 18 90 | ) { 91 | setValue(NSAttributedString(string: "\n" + message, attributes: [ 92 | .font: UIFont.systemFont(ofSize: size), 93 | .foregroundColor: color 94 | ]), forKey: "attributedMessage") 95 | } 96 | } 97 | 98 | public extension UIAlertAction { 99 | func setImage(_ image: UIImage) { 100 | setValue(image, forKey: "image") 101 | } 102 | 103 | func setIcon(_ name: String, isSystem: Bool = false) { 104 | if let image = isSystem ? 105 | UIImage(systemName: name) : 106 | UIImage(named: name) 107 | { 108 | setImage(image) 109 | } 110 | } 111 | 112 | func setColor(_ color: UIColor) { 113 | setValue(color, forKey: "titleTextColor") 114 | setValue(color, forKey: "imageTintColor") 115 | } 116 | 117 | func setChecked(_ checked: Bool) { 118 | setValue(checked, forKey: "checked") 119 | } 120 | 121 | func setLeftAligment(_ leftAligment: Bool) { 122 | if leftAligment { 123 | setValue(CATextLayerAlignmentMode.left, forKey: "titleTextAlignment") 124 | } 125 | } 126 | } 127 | 128 | public extension UIViewController { 129 | func present( 130 | _ child: UIViewController, 131 | animated: Bool = true, 132 | sourceView: UIView? = nil, 133 | barButtonItem: UIBarButtonItem? = nil, 134 | completion: (() -> Void)? = nil 135 | ) { 136 | if let popover = child.popoverPresentationController { 137 | if let sourceView = sourceView { 138 | popover.sourceView = sourceView 139 | } else if let barButtonItem = barButtonItem { 140 | popover.barButtonItem = barButtonItem 141 | } 142 | } 143 | present(child, animated: animated, completion: completion) 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /Tests/AlertControllerTests/AlertControllerTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import AlertController 3 | 4 | final class AlertControllerTests: XCTestCase { 5 | } 6 | --------------------------------------------------------------------------------