├── .gitignore ├── .swift-version ├── .travis.yml ├── AAExtensions.png ├── AAExtensions.podspec ├── AAExtensions ├── Assets │ └── .gitkeep └── Classes │ ├── Designables │ ├── Designable+UITextField.swift │ ├── Designable+UIView.swift │ └── Designable+UIViewController.swift │ ├── Extensions │ ├── Basic │ │ ├── AAExtension+Array.swift │ │ ├── AAExtension+Collection.swift │ │ ├── AAExtension+Data.swift │ │ ├── AAExtension+Dictionary.swift │ │ ├── AAExtension+Locale.swift │ │ ├── AAExtension+Sequence.swift │ │ ├── AAExtension+String.swift │ │ └── AAExtensions+URL.swift │ ├── DataTypes │ │ ├── AAExtension+Bool.swift │ │ ├── AAExtension+Double.swift │ │ └── AAExtension+Int.swift │ ├── Other │ │ ├── AAExtension+ArrayElement.swift │ │ ├── AAExtension+Date.swift │ │ ├── AAExtension+DispatchQueue.swift │ │ ├── AAExtension+NSAttributedString.swift │ │ ├── AAExtension+PHAsset.swift │ │ ├── AAExtension+StringProtocol.swift │ │ ├── AAExtensions+Encodable.swift │ │ ├── AAExtensions+FileManager.swift │ │ ├── AAExtensions+IndexPath.swift │ │ └── AAExtensions+Mirror.swift │ └── UI │ │ ├── AAExtension+UIApplication.swift │ │ ├── AAExtension+UIBarButtonItem.swift │ │ ├── AAExtension+UIButton.swift │ │ ├── AAExtension+UICollectionView.swift │ │ ├── AAExtension+UICollectionViewCell.swift │ │ ├── AAExtension+UIControl.swift │ │ ├── AAExtension+UIFont.swift │ │ ├── AAExtension+UIImage.swift │ │ ├── AAExtension+UINavigationController.swift │ │ ├── AAExtension+UIRefreshControl.swift │ │ ├── AAExtension+UIResponder.swift │ │ ├── AAExtension+UIScrollView.swift │ │ ├── AAExtension+UISearchBar.swift │ │ ├── AAExtension+UIStackView.swift │ │ ├── AAExtension+UIStoryboard.swift │ │ ├── AAExtension+UITabBar.swift │ │ ├── AAExtension+UITableView.swift │ │ ├── AAExtension+UITableViewCell.swift │ │ ├── AAExtension+UITextField.swift │ │ ├── AAExtension+UIView.swift │ │ ├── AAExtension+UIViewController.swift │ │ └── AAExtensions+UIColor.swift │ ├── Modules │ ├── AADateRangePicker │ │ ├── AADateRangePickerCell.swift │ │ ├── AADateRangePickerHeaderView.swift │ │ └── AADateRangePickerViewController.swift │ ├── Module+AABindableBarButton.swift │ ├── Module+AABottomSheet.swift │ ├── Module+AADocumentPicker.swift │ ├── Module+AAImagePicker.swift │ ├── Module+AATimer.swift │ ├── Module+AAUpdateModule.swift │ ├── Module+AAUserNotification.swift │ ├── Module+AAWrappedCollectionView.swift │ ├── Module+NSLayoutConstraint │ │ ├── Module+AADualConstantConstraint.swift │ │ ├── Module+AAKeyboardLayoutConstraint.swift │ │ └── Module+AAReversibleConstraint.swift │ ├── Module+UIButton │ │ ├── Module+AABackButton.swift │ │ ├── Module+AAImageButton.swift │ │ └── Module+AALoadingButton.swift │ ├── Module+UICollection │ │ └── Module+AACarouselFlowLayout.swift │ ├── Module+UILabel │ │ ├── Module+AAGradientLabel.swift │ │ ├── Module+AALabelParagraph.swift │ │ ├── Module+AALinedLabel.swift │ │ ├── Module+AAPaddingLabel.swift │ │ ├── Module+AATimerLabel.swift │ │ └── Module+AAVerticalAlignLabel.swift │ ├── Module+UITextFeild │ │ └── Module+AAFloatingTextField.swift │ ├── Module+UITextView │ │ └── Module+AAPlaceholderTextView.swift │ ├── Module+UIView │ │ ├── Module+AABorderLinesView.swift │ │ └── Module+AAGradientView.swift │ └── Modules+UIImageView │ │ ├── Module+AAImageAlligned.swift │ │ └── Module+LoadImage.swift │ └── Shared │ ├── AA_Constants.swift │ ├── AA_ExtensionProvider.swift │ └── AA_Helper.swift ├── Example ├── AAExtensions.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── AAExtensions-Example.xcscheme ├── AAExtensions.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── AAExtensions │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── LaunchScreen.xib │ │ └── Main.storyboard │ ├── Images.xcassets │ │ ├── AA.imageset │ │ │ ├── 17049477.png │ │ │ └── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── Icon-App-20x20@1x.png │ │ │ ├── Icon-App-20x20@2x.png │ │ │ ├── Icon-App-20x20@3x.png │ │ │ ├── Icon-App-29x29@1x.png │ │ │ ├── Icon-App-29x29@2x.png │ │ │ ├── Icon-App-29x29@3x.png │ │ │ ├── Icon-App-40x40@1x.png │ │ │ ├── Icon-App-40x40@2x.png │ │ │ ├── Icon-App-40x40@3x.png │ │ │ ├── Icon-App-57x57@1x.png │ │ │ ├── Icon-App-57x57@2x.png │ │ │ ├── Icon-App-60x60@2x.png │ │ │ ├── Icon-App-60x60@3x.png │ │ │ ├── Icon-App-72x72@1x.png │ │ │ ├── Icon-App-72x72@2x.png │ │ │ ├── Icon-App-76x76@1x.png │ │ │ ├── Icon-App-76x76@2x.png │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ ├── Icon-Small-50x50@1x.png │ │ │ └── Icon-Small-50x50@2x.png │ │ └── Contents.json │ ├── Info.plist │ └── ViewController.swift ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── AAExtensions.podspec.json │ ├── Manifest.lock │ ├── Pods.xcodeproj │ │ └── project.pbxproj │ └── Target Support Files │ │ ├── AAExtensions │ │ ├── AAExtensions-Info.plist │ │ ├── AAExtensions-dummy.m │ │ ├── AAExtensions-prefix.pch │ │ ├── AAExtensions-umbrella.h │ │ ├── AAExtensions.debug.xcconfig │ │ ├── AAExtensions.modulemap │ │ ├── AAExtensions.release.xcconfig │ │ └── AAExtensions.xcconfig │ │ ├── Pods-AAExtensions_Example │ │ ├── Pods-AAExtensions_Example-Info.plist │ │ ├── Pods-AAExtensions_Example-acknowledgements.markdown │ │ ├── Pods-AAExtensions_Example-acknowledgements.plist │ │ ├── Pods-AAExtensions_Example-dummy.m │ │ ├── Pods-AAExtensions_Example-frameworks.sh │ │ ├── Pods-AAExtensions_Example-umbrella.h │ │ ├── Pods-AAExtensions_Example.debug.xcconfig │ │ ├── Pods-AAExtensions_Example.modulemap │ │ └── Pods-AAExtensions_Example.release.xcconfig │ │ └── Pods-AAExtensions_Tests │ │ ├── Pods-AAExtensions_Tests-Info.plist │ │ ├── Pods-AAExtensions_Tests-acknowledgements.markdown │ │ ├── Pods-AAExtensions_Tests-acknowledgements.plist │ │ ├── Pods-AAExtensions_Tests-dummy.m │ │ ├── Pods-AAExtensions_Tests-umbrella.h │ │ ├── Pods-AAExtensions_Tests.debug.xcconfig │ │ ├── Pods-AAExtensions_Tests.modulemap │ │ └── Pods-AAExtensions_Tests.release.xcconfig └── Tests │ ├── Info.plist │ └── Tests.swift ├── LICENSE ├── README.md └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | # Pods/ 38 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.6 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/AAExtensions.xcworkspace -scheme AAExtensions-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /AAExtensions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/AAExtensions.png -------------------------------------------------------------------------------- /AAExtensions.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint AAExtensions.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'AAExtensions' 11 | s.version = '1.2.6' 12 | s.summary = 'AAExtensions are a set of UI Extensions and Helper functions for iOS applications which is written in Swift 5.0' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | AAExtensions are a set of UI Extensions and Helper functions for iOS applications which is written in Swift 5.0. 22 | DESC 23 | 24 | s.homepage = 'https://github.com/EngrAhsanAli/AAExtensions' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { :type => 'MIT', :file => 'LICENSE' } 27 | s.author = { 'EngrAhsanAli' => 'hafiz.m.ahsan.ali@gmail.com' } 28 | s.source = { :git => 'https://github.com/EngrAhsanAli/AAExtensions.git', :tag => s.version.to_s } 29 | # s.social_media_url = 'https://twitter.com/' 30 | 31 | s.ios.deployment_target = '9.0' 32 | s.swift_version = '5.0' 33 | s.source_files = 'AAExtensions/Classes/**/*' 34 | 35 | # s.resource_bundles = { 36 | # 'AAExtensions' => ['AAExtensions/Assets/*.png'] 37 | # } 38 | 39 | # s.public_header_files = 'Pod/Classes/**/*.h' 40 | # s.frameworks = 'UIKit', 'MapKit' 41 | # s.dependency 'AFNetworking', '~> 2.3' 42 | end 43 | -------------------------------------------------------------------------------- /AAExtensions/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/AAExtensions/Assets/.gitkeep -------------------------------------------------------------------------------- /AAExtensions/Classes/Designables/Designable+UITextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Designable+UITextField.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- UITextfield IBDesignable 28 | @IBDesignable 29 | public extension UITextField { 30 | 31 | @IBInspectable var AAPaddingLeft: CGFloat { 32 | get { leftView!.frame.size.width } 33 | set { 34 | leftView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height)) 35 | leftViewMode = .always 36 | } 37 | } 38 | 39 | @IBInspectable var AAPaddingRight: CGFloat { 40 | get { rightView!.frame.size.width } 41 | set { 42 | rightView = UIView(frame: CGRect(x: 0, y: 0, width: newValue, height: frame.size.height)) 43 | rightViewMode = .always 44 | } 45 | } 46 | 47 | @IBInspectable 48 | var AAShouldDismiss: Bool { 49 | get { self.AAShouldDismiss } 50 | set (value) { 51 | if value { 52 | self.addTarget(nil, action:#selector(UIView.endEditing(_ :)), for:.editingDidEndOnExit) 53 | } 54 | } 55 | } 56 | 57 | @IBInspectable var AAMaxLength: Int { 58 | get { 59 | if let length = objc_getAssociatedObject(self, &AA_AssociationKeyMaxLength) as? Int { 60 | return length 61 | } else { 62 | return Int.max 63 | } 64 | } 65 | set { 66 | objc_setAssociatedObject(self, &AA_AssociationKeyMaxLength, newValue, .OBJC_ASSOCIATION_RETAIN) 67 | addTarget(self, action: #selector(checkMaxLength), for: .editingChanged) 68 | } 69 | } 70 | 71 | @objc private func checkMaxLength(textField: UITextField) { 72 | guard let prospectiveText = self.text, 73 | prospectiveText.count > AAMaxLength 74 | else { return } 75 | 76 | let selection = selectedTextRange 77 | let indexEndOfText = prospectiveText.index(prospectiveText.startIndex, offsetBy: AAMaxLength) 78 | let substring = prospectiveText[.. ()) rethrows { 37 | self = try map { el in 38 | var el = el 39 | try transform(&el) 40 | return el 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtension+Collection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Collection.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- Collection 27 | public extension Collection { 28 | 29 | subscript(aa_optional i: Index) -> Iterator.Element? { 30 | return self.indices.contains(i) ? self[i] : nil 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtension+Data.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Data.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 09/06/2019. 6 | // 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 | public extension Data { 28 | 29 | var aa_toJson: Any? { 30 | do { 31 | return try JSONSerialization.jsonObject(with: self) as Any 32 | } catch { 33 | print("\(AA_TAG) Error Parsing JSON from Data") 34 | } 35 | return nil 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtension+Dictionary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Dictionary.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | // MARK:- Dictionary 28 | public extension Dictionary { 29 | 30 | // dict[keyPath: "countries.japan.language"] = "nihongo" 31 | subscript(aa_keyPath keyPath: String) -> Any? { 32 | get { 33 | guard let keyPath = Dictionary.keyPathKeys(forKeyPath: keyPath) 34 | else { return nil } 35 | return getValue(forKeyPath: keyPath) 36 | } 37 | set { 38 | guard let keyPath = Dictionary.keyPathKeys(forKeyPath: keyPath), 39 | let newValue = newValue else { return } 40 | self.setValue(newValue, forKeyPath: keyPath) 41 | } 42 | } 43 | 44 | var aa_json: String? { 45 | do { 46 | let jsonData = try JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) 47 | return String(bytes: jsonData, encoding: .utf8) 48 | } catch { 49 | debugPrint("AAExtensions:- ", error.localizedDescription) 50 | return nil 51 | } 52 | } 53 | 54 | func aa_printJson() { 55 | print(aa_json ?? "\(AA_TAG) Invalid JSON String") 56 | } 57 | 58 | static func += (left: inout Dictionary, right: Dictionary) { 59 | for (key, value) in right { 60 | left[key] = value 61 | } 62 | } 63 | 64 | subscript(i: Int) -> (key: Key, value: Value) { 65 | return self[index(startIndex, offsetBy: i)] 66 | } 67 | 68 | func aa_append(_ dict: [Key: Value]) -> [Key: Value] { 69 | var result = self 70 | dict.forEach { key, value in result[key] = value } 71 | return result 72 | } 73 | } 74 | 75 | 76 | // MARK:- Internal helpers 77 | fileprivate extension Dictionary { 78 | 79 | static private func keyPathKeys(forKeyPath: String) -> [Key]? { 80 | let keys = forKeyPath.components(separatedBy: ".") 81 | .reversed().compactMap({ $0 as? Key }) 82 | return keys.isEmpty ? nil : keys 83 | } 84 | 85 | // recursively (attempt to) access queried subdictionaries 86 | // (keyPath will never be empty here; the explicit unwrapping is safe) 87 | private func getValue(forKeyPath keyPath: [Key]) -> Any? { 88 | guard let value = self[keyPath.last!] else { return nil } 89 | return keyPath.count == 1 ? value : (value as? [Key: Any]) 90 | .flatMap { $0.getValue(forKeyPath: Array(keyPath.dropLast())) } 91 | } 92 | 93 | // recursively (attempt to) access the queried subdictionaries to 94 | // finally replace the "inner value", given that the key path is valid 95 | private mutating func setValue(_ value: Any, forKeyPath keyPath: [Key]) { 96 | guard self[keyPath.last!] != nil else { return } 97 | if keyPath.count == 1 { 98 | (value as? Value).map { self[keyPath.last!] = $0 } 99 | } 100 | else if var subDict = self[keyPath.last!] as? [Key: Value] { 101 | subDict.setValue(value, forKeyPath: Array(keyPath.dropLast())) 102 | (subDict as? Value).map { self[keyPath.last!] = $0 } 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtension+Locale.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Locale.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 15/06/2019. 6 | // 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 | public extension NSLocale { 27 | 28 | /// returns current country name and country code 29 | static var aa_currentCountry: (String, String) { 30 | let countryLocale = NSLocale.current 31 | let countryCode = countryLocale.regionCode! 32 | let country = (countryLocale as NSLocale) 33 | .displayName(forKey: NSLocale.Key.countryCode, value: countryCode)! 34 | return (country, countryCode) 35 | } 36 | 37 | class func aa_languageName(identifier: String) -> String { 38 | let locale = NSLocale(localeIdentifier: identifier) 39 | return locale.displayName(forKey: NSLocale.Key.identifier , value: identifier)! 40 | } 41 | 42 | static var aa_currentLocale: String { 43 | Bundle.main.preferredLocalizations.first! 44 | } 45 | } 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtension+Sequence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Sequence.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | // MARK:- Sequence 27 | public extension Sequence { 28 | func aa_group(by key: (Iterator.Element) -> U) -> [U:[Iterator.Element]] { 29 | return Dictionary.init(grouping: self, by: key) 30 | } 31 | } 32 | 33 | // MARK: - Sequence 34 | public extension Sequence where Iterator.Element: Hashable { 35 | var aa_unique: [Iterator.Element] { 36 | var seen: [Iterator.Element: Bool] = [:] 37 | return self.filter { seen.updateValue(true, forKey: $0) == nil } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Basic/AAExtensions+URL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+URL.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/05/04. 6 | // 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 | import MobileCoreServices 27 | 28 | public extension URL { 29 | 30 | var mimeType: String { 31 | let pathExtension = self.pathExtension 32 | if let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as NSString, nil)?.takeRetainedValue() { 33 | if let mimetype = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType)?.takeRetainedValue() { 34 | return mimetype as String 35 | } 36 | } 37 | return "application/octet-stream" 38 | } 39 | 40 | var containsImage: Bool { 41 | guard let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType as CFString, nil)?.takeRetainedValue() else { 42 | return false 43 | } 44 | return UTTypeConformsTo(uti, kUTTypeImage) 45 | } 46 | 47 | var containsAudio: Bool { 48 | guard let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType as CFString, nil)?.takeRetainedValue() else { 49 | return false 50 | } 51 | return UTTypeConformsTo(uti, kUTTypeAudio) 52 | } 53 | 54 | var containsVideo: Bool { 55 | guard let uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, mimeType as CFString, nil)?.takeRetainedValue() else { 56 | return false 57 | } 58 | return UTTypeConformsTo(uti, kUTTypeMovie) 59 | } 60 | 61 | var currentMimeType: String? { 62 | if self.containsImage { return "image/png" } 63 | if self.containsAudio { return "audio/mp3" } 64 | if self.containsVideo { return "video/mp4" } 65 | return nil 66 | } 67 | 68 | var attributes: [FileAttributeKey : Any]? { 69 | do { 70 | return try FileManager.default.attributesOfItem(atPath: path) 71 | } catch let error as NSError { 72 | print("FileAttribute error: \(error)") 73 | } 74 | return nil 75 | } 76 | 77 | var fileSize: UInt64 { attributes?[.size] as? UInt64 ?? UInt64(0) } 78 | 79 | var fileSizeString: String { ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file) } 80 | 81 | var creationDate: Date? { attributes?[.creationDate] as? Date } 82 | 83 | var fileSizeMb: Float? { 84 | let formatter = ByteCountFormatter() 85 | formatter.allowedUnits = [.useMB] 86 | formatter.countStyle = .file 87 | let string = formatter.string(fromByteCount: Int64(fileSize)) 88 | if let digit = string.components(separatedBy: " ").first, 89 | let value = Float(digit) { 90 | return value 91 | } 92 | return nil 93 | } 94 | 95 | func aa_valueOf(_ queryParamaterName: String) -> String? { 96 | guard let url = URLComponents(string: self.absoluteString) else { return nil } 97 | return url.queryItems?.first(where: { $0.name == queryParamaterName })?.value 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/DataTypes/AAExtension+Bool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Bool.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | // MARK:- Bool 27 | public extension Bool { 28 | 29 | var aa_intValue: Int { self ? 1 : 0 } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/DataTypes/AAExtension+Double.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Double.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | // MARK:- Double 28 | public extension Double { 29 | 30 | var aa_secondsTommss: String { 31 | let minutes = Int(self) / 60 % 60 32 | let seconds = Int(self) % 60 33 | return String(format:"%02i:%02i", minutes, seconds) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/DataTypes/AAExtension+Int.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+Int.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | //MARK:- Int 28 | public extension Int { 29 | 30 | var aa_to_mmss : String { "\(((self % 3600) / 60).aa_twoDigit):\(((self % 3600) % 60).aa_twoDigit)" } 31 | 32 | var aa_twoDigit: String { String(format: "%02d", self) } 33 | 34 | var aa_toString: String { String(self) } 35 | 36 | var aa_boolValue: Bool { self != 0 } 37 | 38 | var aa_nonNegative: Int { self > 0 ? self : 0 } 39 | 40 | func aa_toLocalizedString(locale: Locale = .current) -> String { 41 | let formatter = NumberFormatter() 42 | formatter.locale = locale // Locale(identifier: "ar") 43 | return formatter.string(from: NSNumber(integerLiteral: self)) ?? aa_toString 44 | } 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtension+ArrayElement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+ArrayElement.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan ALI on 25/05/2019. 6 | // 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 | // MARK: - Array UITextField 28 | public extension Array where Element == UITextField { 29 | 30 | func aa_clear() { 31 | forEach { 32 | $0.text = String() 33 | $0.attributedText = NSAttributedString(string: String()) 34 | } 35 | } 36 | 37 | func aa_enabled(_ isEnabled: Bool) { forEach { $0.isEnabled = isEnabled } } 38 | 39 | var aa_validateEmpty: Bool { (filter { $0.text?.isEmpty ?? false }.count > 0) } 40 | 41 | } 42 | 43 | // MARK: - Array Equatable 44 | public extension Array where Element: Equatable { 45 | 46 | func aa_indexes(of item: Element) -> [Int] { 47 | enumerated().compactMap { $0.element == item ? $0.offset : nil } 48 | } 49 | 50 | } 51 | 52 | // MARK: - Array UIView 53 | public extension Sequence where Iterator.Element: UIView { 54 | 55 | func aa_setVisibility(_ flag: Bool) { forEach { $0.isHidden = !flag } } 56 | 57 | } 58 | 59 | // MARK: - Array AAReversibleConstraint 60 | public extension Array where Element == AAReversibleConstraint { 61 | 62 | func setVisibility(_ isHidden: Bool) { forEach { $0.showHide(isHidden) } } 63 | 64 | } 65 | 66 | // MARK: - RangeReplaceableCollection 67 | public extension RangeReplaceableCollection where Element: Equatable { 68 | 69 | mutating func aa_appendOrRemove(_ element: Element) { 70 | if let index = firstIndex(of: element) { remove(at: index) } 71 | else { insert(element, at: endIndex) } 72 | } 73 | 74 | mutating func aa_appendUnique(_ element: Element) { 75 | guard firstIndex(of: element) == nil else { return } 76 | insert(element, at: endIndex) 77 | } 78 | 79 | mutating func aa_remove(_ element: Element) { 80 | guard let index = firstIndex(of: element) else { return } 81 | remove(at: index) 82 | } 83 | } 84 | 85 | public extension Array { 86 | 87 | mutating func aa_move(at oldIndex: Int, to newIndex: Int) { 88 | if newIndex >= count || newIndex < 0 { return } 89 | self.insert(self.remove(at: oldIndex), at: newIndex) 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtension+DispatchQueue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+DispatchQueue.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan ALI on 25/05/2019. 6 | // 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 | public extension DispatchQueue { 27 | 28 | class func aa_performBackground(delay: Double = 0.0, 29 | background: AACompletionVoid? = nil, 30 | completion: AACompletionVoid? = nil) { 31 | DispatchQueue.global(qos: .background).async { 32 | background?() 33 | if let completion = completion { 34 | DispatchQueue.main.asyncAfter(deadline: .now() + delay, 35 | execute: { completion() }) 36 | } 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtension+PHAsset.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+PHAsset.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 Photos 28 | 29 | //MARK:- PHAsset 30 | public extension PHAsset { 31 | 32 | var aa_image: UIImage? { 33 | var img: UIImage? 34 | let manager = PHImageManager.default() 35 | let options = PHImageRequestOptions() 36 | options.version = .original 37 | options.isSynchronous = true 38 | manager.requestImageData(for: self, options: options) { data, _, _, _ in 39 | if let data = data { 40 | img = UIImage(data: data) 41 | } 42 | } 43 | return img 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtension+StringProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+StringProtocol.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 15/06/2019. 6 | // 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 | // MARK: - StringProtocol 28 | public extension StringProtocol { 29 | 30 | func aa_nsRange(from range: Range) -> NSRange { .init(range, in: self) } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtensions+Encodable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+Encodable.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/01/17. 6 | // 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 | public extension Encodable { 27 | 28 | var aa_dictionary: [String: Any] { 29 | (try? JSONSerialization.jsonObject(with: JSONEncoder().encode(self))) as? [String: Any] ?? [:] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtensions+FileManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+FileManager.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/03/11. 6 | // 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 | public extension FileManager { 27 | 28 | func aa_urls(for directory: FileManager.SearchPathDirectory, skipsHiddenFiles: Bool = true ) -> [URL]? { 29 | let documentsURL = urls(for: directory, in: .userDomainMask)[0] 30 | let fileURLs = try? contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil, options: skipsHiddenFiles ? .skipsHiddenFiles : [] ) 31 | return fileURLs 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtensions+IndexPath.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+IndexPath.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/07/17. 6 | // 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 | public extension IndexPath { 27 | 28 | var aa_nextRow: IndexPath { .init(row: row + 1, section: section) } 29 | 30 | var aa_prevRow: IndexPath { .init(row: row + -1, section: section) } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/Other/AAExtensions+Mirror.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+Mirror.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/05/20. 6 | // 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 | public extension Mirror { 27 | 28 | static func aa_filterText(_ text: String, data: Any?, index: Int = 0) -> [Int]? { 29 | var indexes = [Int]() 30 | 31 | if let string = data as? String, string.lowercased().contains(text.lowercased()) { 32 | indexes.append(index) 33 | } 34 | else if let mirror = data as? Mirror { 35 | mirror.children.forEach { 36 | if let result = aa_filterText(text, data: $0.value, index: index + 1) { 37 | indexes.append(contentsOf: result) 38 | } 39 | } 40 | } 41 | else { 42 | if let data = data { 43 | let child = Mirror(reflecting: data) 44 | return aa_filterText(text, data: child, index: index) 45 | } 46 | } 47 | 48 | return (indexes.count > 0 ? indexes : nil) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIBarButtonItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UIBarButtonItem.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan ALI on 25/05/2019. 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 | public extension UIBarButtonItem { 26 | 27 | var aa_isHidden: Bool { 28 | get { return tintColor == .clear } 29 | set { 30 | tintColor = newValue ? .clear : .white 31 | isEnabled = !newValue 32 | isAccessibilityElement = !newValue 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UIButton.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- UIButton 28 | public extension AA where Base: UIButton { 29 | 30 | func setFontIcon(string: String?, 31 | icon: String, 32 | iconColor: UIColor? = nil, 33 | textColor: UIColor?, 34 | iconFont: UIFont, 35 | textFont: UIFont, 36 | state: UIControl.State = .normal, 37 | baseline: Int = 3, 38 | isLeft: Bool) { 39 | 40 | let buttonText = string ?? base.title(for: state) ?? " " 41 | let normalColor = textColor ?? base.titleColor(for: state) 42 | let titleString: String 43 | if isLeft { titleString = .localizedStringWithFormat("%@ \(icon)", buttonText) } 44 | else { titleString = .localizedStringWithFormat("\(icon) %@", buttonText) } 45 | let textRange = NSRange(titleString.range(of: buttonText)!, in: titleString) 46 | let rangeIcon = NSRange(titleString.range(of: icon)!, in: titleString) 47 | 48 | let attrs = NSMutableAttributedString(string: titleString) 49 | attrs.addAttribute(.baselineOffset, value: baseline, range: textRange) 50 | attrs.addAttribute(.font, value: textFont, range: textRange) 51 | attrs.addAttribute(.font, value: iconFont, range: rangeIcon) 52 | if let textColor = textColor { 53 | attrs.addAttribute(.foregroundColor, value: textColor as Any , range: textRange) 54 | } 55 | if let iconColor = iconColor { 56 | attrs.addAttribute(.foregroundColor, value: iconColor , range: rangeIcon) 57 | } 58 | else { 59 | attrs.addAttribute(.foregroundColor, value: normalColor as Any , range: .init(location: 0, length: buttonText.count)) 60 | } 61 | base.setAttributedTitle(attrs, for: state) 62 | 63 | } 64 | 65 | func setBackgroundColor(color: UIColor, forState: UIControl.State) { 66 | base.clipsToBounds = true 67 | UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) 68 | if let context = UIGraphicsGetCurrentContext() { 69 | context.setFillColor(color.cgColor) 70 | context.fill(CGRect(x: 0, y: 0, width: 1, height: 1)) 71 | let colorImage = UIGraphicsGetImageFromCurrentImageContext() 72 | UIGraphicsEndImageContext() 73 | base.setBackgroundImage(colorImage, for: forState) 74 | } 75 | } 76 | 77 | func animateSelection(_ animation: @escaping (() -> ())) { 78 | UIView.transition(with: base, duration: 0.3, 79 | options: base.isSelected ? .transitionFlipFromBottom : .transitionFlipFromTop, 80 | animations: { 81 | self.base.isSelected.toggle() 82 | animation() 83 | }, completion: nil) 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UICollectionView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UICollectionView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- UICollectionView 28 | public extension UICollectionView { 29 | func aa_setItemsInRow(_ inRow: CGFloat = 2, multiplier: CGFloat = 1.5, spacing: CGFloat = 1.0) { 30 | if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout { 31 | let itemSpacing: CGFloat = spacing 32 | let width = self.bounds.width 33 | let size = CGSize(width: (width/inRow)-(itemSpacing*multiplier), height: (width/inRow)-(itemSpacing*multiplier)) 34 | layout.itemSize = size 35 | layout.sectionInset = UIEdgeInsets(top: 0, left: itemSpacing, bottom: 0, right: itemSpacing) 36 | layout.minimumInteritemSpacing = itemSpacing 37 | layout.minimumLineSpacing = itemSpacing 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UICollectionViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UICollectionViewCell.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 12/05/2019. 6 | // 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 | // MARK:- UICollectionViewCell 28 | public extension UICollectionViewCell { 29 | var aa_selectionColor: UIColor { 30 | set { 31 | let view = UIView() 32 | view.backgroundColor = newValue 33 | self.selectedBackgroundView = view 34 | } 35 | get { self.selectedBackgroundView?.backgroundColor ?? .clear } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIControl.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UIControl.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | private class ClosureSleeve { 27 | let closure: ((T) -> Void)? 28 | let sender: T 29 | 30 | init (sender: T, _ closure: ((T) -> Void)?) { 31 | self.closure = closure 32 | self.sender = sender 33 | } 34 | 35 | @objc func invoke() { 36 | closure?(sender) 37 | } 38 | } 39 | 40 | public extension AA where Base: UIControl { 41 | 42 | func addAction(for controlEvent: UIControl.Event = .touchUpInside, _ closure: ((UIControl) -> Void)?) { 43 | let previousSleeve = objc_getAssociatedObject(base, String(controlEvent.rawValue)) 44 | objc_removeAssociatedObjects(previousSleeve as Any) 45 | base.removeTarget(previousSleeve, action: nil, for: controlEvent) 46 | 47 | let sleeve = ClosureSleeve(sender: base, closure) 48 | base.addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvent) 49 | objc_setAssociatedObject(base, String(controlEvent.rawValue), sleeve, .OBJC_ASSOCIATION_RETAIN) 50 | } 51 | 52 | } 53 | 54 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UINavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UINavigationController.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 09/06/2019. 6 | // 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 | // MARK: - UINavigationController 28 | public extension AA where Base: UINavigationController { 29 | 30 | func backToViewController(viewController: Swift.AnyClass) { 31 | for element in base.viewControllers as Array { 32 | if element.isKind(of: viewController) { 33 | base.popToViewController(element, animated: true) 34 | break 35 | } 36 | } 37 | } 38 | 39 | func pop(transitionType type: String = CATransitionType.fade.rawValue, duration: CFTimeInterval = 0.3) { 40 | base.addTransition(transitionType: type, duration: duration) 41 | base.popViewController(animated: false) 42 | } 43 | 44 | func push(viewController vc: UIViewController, transitionType type: String = CATransitionType.fade.rawValue, duration: CFTimeInterval = 0.3) { 45 | base.addTransition(transitionType: type, duration: duration) 46 | base.pushViewController(vc, animated: false) 47 | } 48 | 49 | } 50 | 51 | 52 | fileprivate extension UINavigationController { 53 | 54 | func addTransition(transitionType type: String = CATransitionType.fade.rawValue, duration: CFTimeInterval = 0.3) { 55 | let transition = CATransition() 56 | transition.duration = duration 57 | transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) 58 | transition.type = CATransitionType(rawValue: type) 59 | self.view.layer.add(transition, forKey: nil) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIRefreshControl.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UIRefreshControl.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 16/09/2019. 6 | // 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 | // MARK: - UIRefreshControl 27 | public extension AA where Base: UIRefreshControl { 28 | 29 | /// Trigger the refresh control programmatically 30 | func trigger() { 31 | if let scrollView = base.superview as? UIScrollView { 32 | scrollView.setContentOffset(CGPoint(x: 0, y: scrollView.contentOffset.y - base.frame.height), animated: false) 33 | } 34 | base.beginRefreshing() 35 | base.sendActions(for: .valueChanged) 36 | } 37 | 38 | } 39 | 40 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIResponder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UIResponder.swift 3 | // Extensions 4 | // 5 | // Created by M. Ahsan Ali on 23/05/2021. 6 | // 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 | // MARK:- UIResponder 27 | public extension UIResponder { 28 | private weak static var _currentFirstResponder: UIResponder? = nil 29 | 30 | static var aa_current: UIResponder? { 31 | UIResponder._currentFirstResponder = nil 32 | UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil) 33 | return UIResponder._currentFirstResponder 34 | } 35 | 36 | @objc internal func findFirstResponder(sender: AnyObject) { 37 | UIResponder._currentFirstResponder = self 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIScrollView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UIScrollView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- UIScrollView 28 | public extension AA where Base: UIScrollView { 29 | 30 | @discardableResult 31 | func addRefreshControl(_ completion: @escaping (() -> ())) -> UIRefreshControl { 32 | let refreshControl = UIRefreshControl() 33 | refreshControl.tintColor = .gray 34 | if #available(iOS 10.0, *) { base.refreshControl = refreshControl } 35 | else { base.addSubview(refreshControl) } 36 | refreshControl.aa.addAction(for: .valueChanged) { _ in 37 | refreshControl.endRefreshing() 38 | if refreshControl.isRefreshing { completion() } 39 | } 40 | return refreshControl 41 | } 42 | 43 | func scrollToBottomOffset(_ animated: Bool) { 44 | if base.contentSize.height < base.bounds.size.height { return } 45 | let bottomOffset = CGPoint(x: 0, y: base.contentSize.height - base.bounds.size.height) 46 | base.setContentOffset(bottomOffset, animated: animated) 47 | } 48 | 49 | func isOnBottom(with distance: Float = 10) -> Bool { 50 | let y: Float = Float(base.contentOffset.y) + Float(base.bounds.size.height) + Float(base.contentInset.bottom) 51 | let height = Float(base.contentSize.height) 52 | return y > height + distance 53 | } 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UISearchBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UISearchBar.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/12/17. 6 | // 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 | public extension AA where Base: UISearchBar { 27 | 28 | /// Returns the`UITextField` that is placed inside the text field. 29 | var textField: UITextField { 30 | if #available(iOS 13, *) { return base.searchTextField } 31 | else { return base.value(forKey: "_searchField") as! UITextField } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIStackView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UIStackView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- StackView 28 | @available(iOS 9.0, *) 29 | public extension AA where Base: UIStackView { 30 | 31 | func removeArrangedSubviews(removeConstraints: Bool) { 32 | let removedSubviews = base.arrangedSubviews.reduce([]) { (sum, next) -> [UIView] in 33 | base.removeArrangedSubview(next) 34 | return sum + [next] 35 | } 36 | if removeConstraints { 37 | NSLayoutConstraint.deactivate(removedSubviews.flatMap({ $0.constraints })) 38 | } 39 | removedSubviews.forEach({ $0.removeFromSuperview() }) 40 | } 41 | 42 | func setClickListner(_ callback: @escaping ((Int) -> ())) { 43 | base.isUserInteractionEnabled = true 44 | base.aa.onTap { 45 | guard let sender = base.gestureRecognizers?.filter({ ($0 as? UITapGestureRecognizer != nil) }).first else { return } 46 | let view = sender.view 47 | let loc = sender.location(in: view) 48 | guard let subview = view?.hitTest(loc, with: nil) else { return } 49 | callback(subview.tag) 50 | } 51 | base.arrangedSubviews.enumerated().forEach { $0.element.tag = $0.offset } 52 | 53 | } 54 | 55 | func removeView(of type: T.Type) { 56 | guard let index = base.arrangedSubviews.firstIndex(where: {($0 as? T) != nil }) else { return } 57 | let view = base.arrangedSubviews[index] as! T 58 | view.removeFromSuperview() 59 | base.layoutIfNeeded() 60 | } 61 | 62 | func appendUniqueView(view: T?, at index: Int? = nil) { 63 | if let view = view { 64 | removeView(of: T.self) 65 | if let index = index { base.insertArrangedSubview(view, at: index) } 66 | else { base.addArrangedSubview(view) } 67 | } 68 | else { removeView(of: T.self) } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UIStoryboard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UIStoryboard.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 12/05/2019. 6 | // 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 UIKit 28 | 29 | // MARK:- UIStoryboard 30 | public extension UIStoryboard { 31 | 32 | static var aa_main: UIStoryboard? { 33 | guard let name = Bundle.main.object(forInfoDictionaryKey: "UIMainStoryboardFile") as? String 34 | else { return nil } 35 | return UIStoryboard(name: name, bundle: .main) 36 | } 37 | 38 | func aa_viewController(withClass name: T.Type) -> T? { 39 | instantiateViewController(withIdentifier: String(describing: name)) as? T 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UITableView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UITableView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | public extension AA where Base: UITableView { 28 | 29 | var lastSection: Int { base.numberOfSections > 0 ? base.numberOfSections - 1 : 0 } 30 | 31 | func safeScrollToRow(at indexPath: IndexPath, scrollPosition: UITableView.ScrollPosition, animated: Bool) { 32 | guard indexPath.section < base.numberOfSections, 33 | indexPath.row < base.numberOfRows(inSection: indexPath.section) else { return } 34 | base.scrollToRow(at: indexPath, at: scrollPosition, animated: animated) 35 | } 36 | 37 | func insertRowAtBottom(_ scrollToBottom: Bool = true) { 38 | DispatchQueue.main.async { 39 | let lastSection = base.numberOfSections - 1 40 | let lastRowIndex = base.numberOfRows(inSection: lastSection) 41 | let indexPath = IndexPath(row: lastRowIndex, section: lastSection) 42 | base.insertRows(at: [indexPath], with: .none) 43 | if scrollToBottom { base.scrollToRow(at: indexPath, at: .none, animated: false) } 44 | } 45 | } 46 | 47 | func reloadToLastRow(_ lastRow: Int) { 48 | DispatchQueue.main.async { 49 | let lastSection = base.numberOfSections - 1 50 | let lastRowIndex = base.numberOfRows(inSection: lastSection) 51 | guard lastRowIndex > lastRow else { return } 52 | let indexPath = IndexPath(row: lastRowIndex - lastRow, section: lastSection) 53 | base.reloadRows(at: [indexPath], with: .automatic) 54 | } 55 | } 56 | 57 | func scrollToBottom(_ animated: Bool = true) { 58 | DispatchQueue.main.async { 59 | if (base.numberOfSections > 0) { 60 | let lastSection = base.numberOfSections - 1 61 | let rows = base.numberOfRows(inSection: lastSection) 62 | if (rows > 0 ) { 63 | let lastRowIndex = rows - 1 64 | let indexPath = IndexPath(row: lastRowIndex, section: lastSection) 65 | base.scrollToRow(at: indexPath, at: .bottom, animated: animated) 66 | } 67 | } 68 | } 69 | } 70 | 71 | func setOffsetToBottom(animated: Bool) { 72 | base.setContentOffset(CGPoint(x: 0, y: base.contentSize.height - base.frame.size.height), animated: true) 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UITableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extension+UITableViewCell.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | // MARK:- UITableViewCell 28 | public extension UITableViewCell { 29 | var aa_selectionColor: UIColor { 30 | set { 31 | let view = UIView() 32 | view.backgroundColor = newValue 33 | self.selectedBackgroundView = view 34 | } 35 | get { self.selectedBackgroundView?.backgroundColor ?? .clear } 36 | } 37 | } 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtension+UITextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtension+UITextField.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan ALI on 25/05/2019. 6 | // 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 | public extension AA where Base: UITextField { 27 | 28 | func hintColor(_ color: UIColor) { 29 | guard let holder = base.placeholder, !holder.isEmpty else { return } 30 | base.attributedPlaceholder = NSAttributedString(string: holder, attributes: [.foregroundColor: color]) 31 | } 32 | 33 | func setIcon(with size: CGFloat = 18, padding: CGFloat = 8, image: UIImage, isRight: Bool = true) { 34 | 35 | let outerView = UIView(frame: CGRect(x: 0, y: 0, width: size+padding, height: size)) 36 | let iconView = UIImageView(frame: CGRect(x: padding, y: 0, width: size, height: size)) 37 | iconView.image = image 38 | outerView.addSubview(iconView) 39 | 40 | if isRight { 41 | base.rightView = outerView 42 | base.rightViewMode = .always 43 | } 44 | else { 45 | base.leftView = outerView 46 | base.leftViewMode = .always 47 | } 48 | } 49 | 50 | func inputDatePicker(completion: ((String) -> ())?) { 51 | 52 | let datePicker = UIDatePicker() 53 | datePicker.datePickerMode = .date 54 | base.inputView = datePicker 55 | 56 | let toolBar = UIToolbar() 57 | 58 | let flexible = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil) 59 | let cancel = AABindableBarButton(systemItem: .cancel) { 60 | base.resignFirstResponder() 61 | } 62 | let doneBtn = AABindableBarButton(systemItem: .done) { 63 | let dateformatter = DateFormatter() 64 | dateformatter.dateStyle = .medium 65 | base.text = dateformatter.string(from: datePicker.date) 66 | base.resignFirstResponder() 67 | completion?(base.text ?? "") 68 | } 69 | 70 | toolBar.setItems([cancel, flexible, doneBtn], animated: false) 71 | toolBar.sizeToFit() 72 | base.inputAccessoryView = toolBar 73 | 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Extensions/UI/AAExtensions+UIColor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AAExtensions+UIColor.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/08/25. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension UIColor { 11 | 12 | class func aa_fromHex(_ hex: String) -> UIColor? { 13 | var cString:String = hex.trimmingCharacters(in: .whitespacesAndNewlines).uppercased() 14 | 15 | if (cString.hasPrefix("#")) { 16 | cString.remove(at: cString.startIndex) 17 | } 18 | 19 | if ((cString.count) != 6) { 20 | return nil 21 | } 22 | 23 | var rgbValue:UInt64 = 0 24 | Scanner(string: cString).scanHexInt64(&rgbValue) 25 | 26 | return UIColor( 27 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, 28 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, 29 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0, 30 | alpha: CGFloat(1.0) 31 | ) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/AADateRangePicker/AADateRangePickerCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AADateRangePickerCell.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/05/23. 6 | // 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 | class AADateRangePickerCell: UICollectionViewCell { 27 | 28 | var defaultTextColor = UIColor.darkGray 29 | var highlightedColor = UIColor(white: 0.9, alpha: 1.0) 30 | var disabledColor = UIColor.lightGray 31 | 32 | var selectedColor: UIColor! 33 | 34 | var date: Date? 35 | var selectedView: UIView? 36 | var halfBackgroundView: UIView? 37 | var roundHighlightView: UIView? 38 | 39 | var label: UILabel! 40 | 41 | override init(frame: CGRect) { 42 | super.init(frame: frame) 43 | initLabel() 44 | } 45 | 46 | required init?(coder aDecoder: NSCoder) { 47 | super.init(coder: aDecoder)! 48 | initLabel() 49 | } 50 | 51 | func initLabel() { 52 | label = UILabel(frame: frame) 53 | label.center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2) 54 | label.textAlignment = .center 55 | self.addSubview(label) 56 | } 57 | 58 | func reset() { 59 | self.backgroundColor = .clear 60 | label.textColor = defaultTextColor 61 | label.backgroundColor = .clear 62 | if selectedView != nil { 63 | selectedView?.removeFromSuperview() 64 | selectedView = nil 65 | } 66 | if halfBackgroundView != nil { 67 | halfBackgroundView?.removeFromSuperview() 68 | halfBackgroundView = nil 69 | } 70 | if roundHighlightView != nil { 71 | roundHighlightView?.removeFromSuperview() 72 | roundHighlightView = nil 73 | } 74 | } 75 | 76 | func select() { 77 | let width = self.frame.size.width 78 | let height = self.frame.size.height 79 | selectedView = UIView(frame: CGRect(x: (width - height) / 2, y: 0, width: height, height: height)) 80 | selectedView?.backgroundColor = selectedColor 81 | selectedView?.layer.cornerRadius = height / 2 82 | self.addSubview(selectedView!) 83 | self.sendSubviewToBack(selectedView!) 84 | label.textColor = UIColor.white 85 | } 86 | 87 | func highlightRight() { 88 | let width = self.frame.size.width 89 | let height = self.frame.size.height 90 | halfBackgroundView = UIView(frame: CGRect(x: width / 2, y: 0, width: width / 2, height: height)) 91 | halfBackgroundView?.backgroundColor = highlightedColor 92 | self.addSubview(halfBackgroundView!) 93 | self.sendSubviewToBack(halfBackgroundView!) 94 | addRoundHighlightView() 95 | } 96 | 97 | func highlightLeft() { 98 | let width = self.frame.size.width 99 | let height = self.frame.size.height 100 | halfBackgroundView = UIView(frame: CGRect(x: 0, y: 0, width: width / 2, height: height)) 101 | halfBackgroundView?.backgroundColor = highlightedColor 102 | self.addSubview(halfBackgroundView!) 103 | self.sendSubviewToBack(halfBackgroundView!) 104 | addRoundHighlightView() 105 | } 106 | 107 | func addRoundHighlightView() { 108 | let width = self.frame.size.width 109 | let height = self.frame.size.height 110 | roundHighlightView = UIView(frame: CGRect(x: (width - height) / 2, y: 0, width: height, height: height)) 111 | roundHighlightView?.backgroundColor = highlightedColor 112 | roundHighlightView?.layer.cornerRadius = height / 2 113 | self.addSubview(roundHighlightView!) 114 | self.sendSubviewToBack(roundHighlightView!) 115 | } 116 | 117 | func highlight() { 118 | self.backgroundColor = highlightedColor 119 | } 120 | 121 | func disable() { 122 | label.textColor = disabledColor 123 | } 124 | 125 | } 126 | 127 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/AADateRangePicker/AADateRangePickerHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AADateRangePickerHeaderView.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/05/23. 6 | // 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 | class AADateRangePickerHeaderView: UICollectionReusableView { 27 | 28 | var label: UILabel! 29 | 30 | override init(frame: CGRect) { 31 | super.init(frame: frame) 32 | initLabel() 33 | } 34 | 35 | required init?(coder aDecoder: NSCoder) { 36 | super.init(coder: aDecoder)! 37 | initLabel() 38 | } 39 | 40 | func initLabel() { 41 | label = UILabel(frame: frame) 42 | label.center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2) 43 | label.textAlignment = .center 44 | self.addSubview(label) 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+AABindableBarButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AABindableBarButton.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/06/17. 6 | // 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 | public class AABindableBarButton: UIBarButtonItem { 27 | private var actionHandler: (() -> ())? 28 | 29 | public convenience init(image: UIImage?, actionHandler: (() -> ())?) { 30 | self.init(image: image, style: .plain, target: nil, action: #selector(barButtonItemPressed)) 31 | self.target = self 32 | self.actionHandler = actionHandler 33 | } 34 | 35 | public convenience init(systemItem: UIBarButtonItem.SystemItem, actionHandler: (() -> ())?) { 36 | self.init(barButtonSystemItem: systemItem, target: nil, action: #selector(barButtonItemPressed)) 37 | self.target = self 38 | self.actionHandler = actionHandler 39 | } 40 | public convenience init(title: String?, font: UIFont, foregroundColor: UIColor, actionHandler: (() -> ())?) { 41 | self.init(title: title, style: .plain, target: nil, action: #selector(barButtonItemPressed)) 42 | self.target = self 43 | setTitleTextAttributes([.font : font, .foregroundColor : foregroundColor], for: .normal) 44 | setTitleTextAttributes([.font : font, .foregroundColor : foregroundColor], for: .highlighted) 45 | self.actionHandler = actionHandler 46 | } 47 | 48 | @objc func barButtonItemPressed(sender: UIBarButtonItem) { 49 | actionHandler?() 50 | } 51 | } 52 | 53 | final class BindableGestureRecognizer: UITapGestureRecognizer { 54 | 55 | var _action: AACompletionVoid 56 | 57 | init(_ action: @escaping AACompletionVoid) { 58 | self._action = action 59 | super.init(target: nil, action: nil) 60 | self.addTarget(self, action: #selector(execute)) 61 | } 62 | 63 | @objc private func execute() { 64 | _action() 65 | } 66 | } 67 | 68 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+AATimer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AATimer.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 01/06/2019. 6 | // 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 | /// AATimer 27 | open class AATimer { 28 | public typealias Tick = () -> Void 29 | open var timer: Timer? 30 | private var interval: TimeInterval 31 | private var repeats: Bool 32 | private var triggerOnInit: Bool 33 | private var tick: Tick 34 | 35 | public init(interval: TimeInterval, repeats: Bool, triggerOnInit: Bool, onTick: @escaping Tick) { 36 | self.interval = interval 37 | self.repeats = repeats 38 | self.tick = onTick 39 | self.triggerOnInit = triggerOnInit 40 | } 41 | 42 | open func start(){ 43 | if triggerOnInit { 44 | update() 45 | } 46 | 47 | timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(update), userInfo: nil, repeats: true) 48 | } 49 | 50 | open func stop(){ 51 | timer?.invalidate() 52 | } 53 | 54 | @objc func update() { 55 | tick() 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+AAUpdateModule.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAUpdateModule.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/05/2019. 6 | // 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 | /// AAUpdateModule 28 | open class AAUpdateModule: NSObject { 29 | 30 | var countryParam: String? 31 | 32 | public init(countryCode: String?) { 33 | if let countryCode = countryCode { 34 | self.countryParam = "&country=\(countryCode)" 35 | } 36 | } 37 | 38 | open func fetchUpdate(completion: @escaping () -> ()) { 39 | guard let info = Bundle.main.infoDictionary, 40 | let currentVersion = info["CFBundleShortVersionString"] as? String, 41 | let identifier = info["CFBundleIdentifier"] as? String, 42 | let url = URL(string: "http://itunes.apple.com/lookup?bundleId=\(identifier)\(countryParam ?? "")") else { return } 43 | 44 | URLSession.shared.dataTask(with: url) { (data, response, error) in 45 | do { 46 | if let error = error { throw error } 47 | guard let data = data else { throw VersionError.invalidResponse } 48 | let result = try JSONDecoder().decode(LookupResult.self, from: data) 49 | guard let info = result.results.first else { throw VersionError.invalidResponse } 50 | 51 | let appStoreAppVersion = info.version.replacingOccurrences(of: ".", with: "").aa_toInt 52 | let currentVersion = currentVersion.replacingOccurrences(of: ".", with: "").aa_toInt 53 | 54 | if appStoreAppVersion > currentVersion { 55 | DispatchQueue.main.async(execute: completion) 56 | } 57 | 58 | } catch { print(error) } 59 | }.resume() 60 | } 61 | 62 | enum VersionError: Error { 63 | case invalidBundleInfo, invalidResponse 64 | } 65 | 66 | class LookupResult: Decodable { 67 | var results: [AppInfo] 68 | } 69 | 70 | class AppInfo: Decodable { 71 | var version: String 72 | var trackViewUrl: String 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+AAUserNotification.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAUserNotification.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/05/04. 6 | // 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 | import Foundation 27 | 28 | public enum AAPermissionState: Int { 29 | case notDetermined = 0 30 | case denied = 1 31 | case authorized = 2 32 | case provisional = 3 33 | case granted = -10 34 | case unknown = -11 35 | 36 | } 37 | 38 | open class AAUserNotification: NSObject { 39 | 40 | var permissionState: AAPermissionState = .unknown { 41 | didSet { 42 | onPermissionChange?(permissionState) 43 | } 44 | } 45 | 46 | open var didReceive: (([AnyHashable : Any]) -> ())? 47 | 48 | open var onPermissionChange: ((AAPermissionState) -> ())? 49 | 50 | open func requestAuthorization() { 51 | 52 | if #available(iOS 10.0, *) { 53 | UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { 54 | [weak self] (granted, error) in 55 | 56 | self?.permissionState = granted ? .granted : .denied 57 | 58 | if !granted { 59 | print("Please enable \"Notifications\" from App Settings.") 60 | } 61 | else { 62 | self?.getNotificationSettings() 63 | } 64 | } 65 | } else { 66 | 67 | let settings = UIUserNotificationSettings(types: [.alert, .sound, .badge], categories: nil) 68 | UIApplication.shared.registerUserNotificationSettings(settings) 69 | UIApplication.shared.registerForRemoteNotifications() 70 | } 71 | 72 | } 73 | 74 | open func openAppSettings() { 75 | 76 | guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else { 77 | return 78 | } 79 | 80 | if UIApplication.shared.canOpenURL(settingsUrl) { 81 | if #available(iOS 10.0, *) { 82 | UIApplication.shared.open(settingsUrl) 83 | } else { 84 | UIApplication.shared.openURL(settingsUrl) 85 | } 86 | } 87 | } 88 | 89 | @available(iOS 10.0, *) 90 | open func getNotificationSettings() { 91 | 92 | UNUserNotificationCenter.current().getNotificationSettings { (settings) in 93 | 94 | self.permissionState = AAPermissionState(rawValue: settings.authorizationStatus.rawValue) ?? .unknown 95 | 96 | guard settings.authorizationStatus == .authorized else { return } 97 | DispatchQueue.main.async { 98 | UIApplication.shared.registerForRemoteNotifications() 99 | } 100 | } 101 | } 102 | 103 | } 104 | 105 | @available(iOS 10, *) 106 | extension AAUserNotification: UNUserNotificationCenterDelegate { 107 | 108 | public func userNotificationCenter(_ center: UNUserNotificationCenter, 109 | willPresent notification: UNNotification, 110 | withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> 111 | Void) { 112 | 113 | let userInfo = notification.request.content.userInfo 114 | print("AAExtensions:- Userinfo :\(userInfo)") 115 | completionHandler([.alert, .badge, .sound]) 116 | 117 | } 118 | 119 | public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { 120 | self.didReceive?(response.notification.request.content.userInfo) 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+NSLayoutConstraint/Module+AADualConstantConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AADualConstantConstraint.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 16/09/2019. 6 | // 7 | 8 | /// MARK:- DualConstantConstraint 9 | public class AADualConstantConstraint: NSLayoutConstraint { 10 | 11 | /// Default Nib constant backup 12 | private var _constant: CGFloat = 0 13 | 14 | @IBInspectable 15 | public var otherConstraint: CGFloat = 0 16 | 17 | override open var constant: CGFloat { 18 | set { super.constant = newValue } 19 | get { 20 | if super.constant != 0 { _constant = super.constant } 21 | return super.constant 22 | } 23 | } 24 | 25 | /// Sets the desired constraint 26 | /// 27 | /// - Parameter isDefault: NIB default constraint 28 | open func setConstraint(_ isDefault: Bool) { 29 | if isDefault { super.constant = _constant } 30 | else { super.constant = otherConstraint } 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+NSLayoutConstraint/Module+AAKeyboardLayoutConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAKeyboardLayoutConstraint.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// AAKeyboardLayoutConstraint 28 | public class AAKeyboardLayoutConstraint: NSLayoutConstraint { 29 | 30 | private var offset : CGFloat = 0 31 | private var keyboardVisibleHeight : CGFloat = 0 32 | 33 | override public func awakeFromNib() { 34 | super.awakeFromNib() 35 | 36 | offset = constant 37 | 38 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShowNotification(_:)), name: UIResponder.keyboardWillShowNotification, object: nil) 39 | NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil) 40 | } 41 | 42 | deinit { 43 | NotificationCenter.default.removeObserver(self) 44 | } 45 | 46 | // MARK: Notification 47 | 48 | @objc private func keyboardWillShowNotification(_ notification: Notification) { 49 | if let userInfo = notification.userInfo { 50 | if let frameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { 51 | let frame = frameValue.cgRectValue 52 | keyboardVisibleHeight = frame.size.height - 50 53 | } 54 | 55 | self.updateConstant() 56 | switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { 57 | case let (.some(duration), .some(curve)): 58 | 59 | let options = UIView.AnimationOptions(rawValue: curve.uintValue) 60 | 61 | UIView.animate( 62 | withDuration: TimeInterval(duration.doubleValue), 63 | delay: 0, 64 | options: options, 65 | animations: { 66 | UIApplication.shared.keyWindow?.layoutIfNeeded() 67 | return 68 | }, completion: { finished in 69 | }) 70 | default: 71 | 72 | break 73 | } 74 | 75 | } 76 | 77 | } 78 | 79 | @objc private func keyboardWillHideNotification(_ notification: NSNotification) { 80 | keyboardVisibleHeight = 0 81 | self.updateConstant() 82 | 83 | if let userInfo = notification.userInfo { 84 | 85 | switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { 86 | case let (.some(duration), .some(curve)): 87 | 88 | let options = UIView.AnimationOptions(rawValue: curve.uintValue) 89 | 90 | UIView.animate( 91 | withDuration: TimeInterval(duration.doubleValue), 92 | delay: 0, 93 | options: options, 94 | animations: { 95 | UIApplication.shared.keyWindow?.layoutIfNeeded() 96 | return 97 | }, completion: { finished in 98 | }) 99 | default: 100 | break 101 | } 102 | } 103 | } 104 | 105 | func updateConstant() { 106 | self.constant = offset + keyboardVisibleHeight 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+NSLayoutConstraint/Module+AAReversibleConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAReversibleConstraint.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// AAReversibleConstraint 27 | public class AAReversibleConstraint: NSLayoutConstraint { 28 | 29 | @IBInspectable 30 | public var isHidden: Bool = false { 31 | didSet (value) { 32 | if value { 33 | _constant = self.constant 34 | self.hide() 35 | } 36 | } 37 | } 38 | 39 | var _constant: CGFloat = 0 40 | 41 | override public var constant: CGFloat { 42 | set { super.constant = newValue } 43 | get { 44 | if super.constant != 0 { _constant = super.constant } 45 | return super.constant 46 | } 47 | } 48 | 49 | open func show() { 50 | guard !isShowing else { return } 51 | DispatchQueue.main.async { super.constant = self._constant } 52 | } 53 | 54 | open func hide() { 55 | guard isShowing else { return } 56 | DispatchQueue.main.async { super.constant = 0 } 57 | } 58 | 59 | open var isShowing: Bool { super.constant != 0 } 60 | 61 | open func toggle() { isShowing ? hide() : show() } 62 | 63 | open func showHide(_ isHidden: Bool) { isHidden ? hide() : show() } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UIButton/Module+AABackButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AABackButton.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 18/03/2019. 6 | // 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 | /// AABackButton 28 | open class AABackButton : UIButton { 29 | 30 | public override init(frame: CGRect) { 31 | super.init(frame: frame) 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | addTarget(self, action: #selector(backButtonAction), for: .touchUpInside) 37 | 38 | } 39 | 40 | @objc private func backButtonAction() { 41 | 42 | guard let root = UIApplication.shared.keyWindow?.rootViewController else { return } 43 | 44 | if let vc = root.presentedViewController as? UINavigationController { 45 | vc.popViewController(animated: true) 46 | } 47 | else if let vc = root as? UINavigationController { 48 | vc.popViewController(animated: true) 49 | } 50 | else { 51 | root.presentedViewController?.dismiss(animated: true, completion: nil) // Dismiss 52 | } 53 | 54 | } 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UIButton/Module+AAImageButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAImageButton.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/05/26. 6 | // 7 | 8 | import Foundation 9 | 10 | @objc open class AAImageButton: UIButton { 11 | 12 | /// Represents horizontal side for the imagePosition attribute 13 | @objc public enum Side: Int { 14 | case left, right 15 | } 16 | 17 | /// The spacing between the button image and the button title 18 | @IBInspectable open var spacing: CGFloat = 0.0 as CGFloat { 19 | didSet { 20 | invalidateIntrinsicContentSize() 21 | } 22 | } 23 | 24 | /// The side of the button to display the image on 25 | @objc open var imagePosition: Side = Side.left { 26 | didSet { 27 | setNeedsLayout() 28 | } 29 | } 30 | 31 | /// IBInspectable accessor for imagePosition 32 | @objc @IBInspectable open var imageOnRight: Bool { 33 | get { 34 | return imagePosition == .right 35 | } 36 | set { 37 | imagePosition = newValue ? .right : .left 38 | } 39 | } 40 | 41 | // MARK: - Spacing 42 | 43 | /** 44 | Controls enabling adjustments of the edgeInsets to realize the spacing. 45 | Increment to enable, decrement to disable. 46 | 47 | Adjustments are enabled for any value > 0 48 | 49 | Should only be used inside intristicContentSize and fooRectForBar methods 50 | */ 51 | private var enableSpacingAdjustments = 0 52 | 53 | override open var contentEdgeInsets: UIEdgeInsets { 54 | get { 55 | let adjustment = (enableSpacingAdjustments > 0) ? (spacing/2) : 0 56 | return super.contentEdgeInsets.adjust(left: adjustment, right: adjustment) 57 | } 58 | set(contentEdgeInsets) { super.contentEdgeInsets = contentEdgeInsets } 59 | } 60 | 61 | override open var titleEdgeInsets: UIEdgeInsets { 62 | get { 63 | let adjustment = (enableSpacingAdjustments > 0) ? (spacing/2) : 0 64 | return super.titleEdgeInsets.adjust(left: adjustment, right: -adjustment) 65 | } 66 | set(titleEdgeInsets) { super.titleEdgeInsets = titleEdgeInsets } 67 | } 68 | 69 | override open var imageEdgeInsets: UIEdgeInsets { 70 | get { 71 | let adjustment = (enableSpacingAdjustments > 0) ? (spacing/2) : 0 72 | return super.imageEdgeInsets.adjust(left: -adjustment, right: adjustment) 73 | } 74 | set(imageEdgeInsets) { super.imageEdgeInsets = imageEdgeInsets } 75 | } 76 | 77 | open override var intrinsicContentSize: CGSize { 78 | enableSpacingAdjustments += 1 79 | let contentSize = super.intrinsicContentSize 80 | enableSpacingAdjustments -= 1 81 | 82 | return contentSize 83 | } 84 | 85 | open override func sizeThatFits(_ size: CGSize) -> CGSize { 86 | enableSpacingAdjustments += 1 87 | let size = super.sizeThatFits(size) 88 | enableSpacingAdjustments -= 1 89 | 90 | return size 91 | } 92 | 93 | open override func contentRect(forBounds bounds: CGRect) -> CGRect { 94 | enableSpacingAdjustments += 1 95 | let contentRect = super.contentRect(forBounds: bounds) 96 | enableSpacingAdjustments -= 1 97 | 98 | return contentRect 99 | } 100 | 101 | 102 | // MARK: - Image Side 103 | 104 | open override func titleRect(forContentRect contentRect: CGRect) -> CGRect { 105 | enableSpacingAdjustments += 1 106 | var titleRect = super.titleRect(forContentRect: contentRect) 107 | let imageRect = super.imageRect(forContentRect: contentRect) 108 | enableSpacingAdjustments -= 1 109 | 110 | if imagePosition == .right { 111 | titleRect.origin.x = imageRect.minX 112 | } 113 | 114 | return titleRect 115 | } 116 | 117 | open override func imageRect(forContentRect contentRect: CGRect) -> CGRect { 118 | enableSpacingAdjustments += 1 119 | let titleRect = super.titleRect(forContentRect: contentRect) 120 | var imageRect = super.imageRect(forContentRect: contentRect) 121 | enableSpacingAdjustments -= 1 122 | 123 | if imagePosition == .right { 124 | imageRect.origin.x = titleRect.maxX - imageRect.width 125 | } 126 | 127 | return imageRect 128 | } 129 | } 130 | 131 | fileprivate extension UIEdgeInsets { 132 | 133 | /** 134 | Relatively adjusts the left and right parameters of a given UIEdgeInsets by the given values 135 | 136 | - parameter left: The value to add to the left parameter of the edge inset 137 | - parameter right: The value to add to the right parameter of the edge inset 138 | 139 | - returns: The adjusted edge inset 140 | */ 141 | func adjust(left: CGFloat, right: CGFloat) -> UIEdgeInsets { 142 | var edgeInsets = self 143 | edgeInsets.left += left 144 | edgeInsets.right += right 145 | 146 | return edgeInsets 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UIButton/Module+AALoadingButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AALoadingButton.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// AALoadingButton for UIButton Indicator 27 | 28 | fileprivate var originalButtonText: String? 29 | fileprivate var activityIndicator: UIActivityIndicatorView! 30 | 31 | public extension AA where Base: UIButton { 32 | 33 | func showLoading(_ color: UIColor = .lightGray) { 34 | originalButtonText = base.titleLabel?.text 35 | base.setTitle("", for: .normal) 36 | 37 | if (activityIndicator == nil) { 38 | let _activityIndicator = UIActivityIndicatorView() 39 | _activityIndicator.hidesWhenStopped = true 40 | _activityIndicator.color = color 41 | activityIndicator = _activityIndicator 42 | } 43 | 44 | activityIndicator.translatesAutoresizingMaskIntoConstraints = false 45 | base.addSubview(activityIndicator) 46 | let xCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: activityIndicator, attribute: .centerX, multiplier: 1, constant: 0) 47 | base.addConstraint(xCenterConstraint) 48 | 49 | let yCenterConstraint = NSLayoutConstraint(item: self, attribute: .centerY, relatedBy: .equal, toItem: activityIndicator, attribute: .centerY, multiplier: 1, constant: 0) 50 | base.addConstraint(yCenterConstraint) 51 | activityIndicator.startAnimating() 52 | } 53 | 54 | func hideLoading() { 55 | base.setTitle(originalButtonText, for: .normal) 56 | activityIndicator.stopAnimating() 57 | originalButtonText = nil 58 | activityIndicator = nil 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AAGradientLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAGradientLabel.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | /// AAGradientLabel 27 | open class AAGradientLabel: UILabel { 28 | public var gradientColors: [CGColor] = [] 29 | 30 | override open func drawText(in rect: CGRect) { 31 | if let gradientColor = drawGradientColor(in: rect, colors: gradientColors) { 32 | self.textColor = gradientColor 33 | } 34 | super.drawText(in: rect) 35 | } 36 | 37 | private func drawGradientColor(in rect: CGRect, colors: [CGColor]) -> UIColor? { 38 | let currentContext = UIGraphicsGetCurrentContext() 39 | currentContext?.saveGState() 40 | defer { currentContext?.restoreGState() } 41 | 42 | let size = rect.size 43 | UIGraphicsBeginImageContextWithOptions(size, false, 0) 44 | guard let gradient = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), 45 | colors: colors as CFArray, 46 | locations: nil) else { return nil } 47 | 48 | let context = UIGraphicsGetCurrentContext() 49 | context?.drawLinearGradient(gradient, 50 | start: CGPoint.zero, 51 | end: CGPoint(x: size.width, y: 0), 52 | options: []) 53 | let gradientImage = UIGraphicsGetImageFromCurrentImageContext() 54 | UIGraphicsEndImageContext() 55 | guard let image = gradientImage else { return nil } 56 | return UIColor(patternImage: image) 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AALabelParagraph.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AALabelParagraph.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | @available(iOS 9.0, *) 28 | @IBDesignable 29 | open class AALabelParagraph: UILabel { 30 | 31 | @IBInspectable open var isHorizontal: Bool = true 32 | @IBInspectable open var firstColor: UIColor = .black 33 | @IBInspectable open var secondOther: UIColor = .black 34 | @IBInspectable open var tabsSize: Int = 1 35 | 36 | override init(frame: CGRect) { 37 | super.init(frame: frame) 38 | sharedInit() 39 | } 40 | 41 | required public init?(coder aDecoder: NSCoder) { 42 | super.init(coder: aDecoder) 43 | sharedInit() 44 | } 45 | 46 | override open func prepareForInterfaceBuilder() { 47 | super.prepareForInterfaceBuilder() 48 | sharedInit() 49 | } 50 | 51 | override open func awakeFromNib() { 52 | super.awakeFromNib() 53 | } 54 | 55 | func sharedInit() { } 56 | 57 | func setAttrText(first: [String], second: [String]) { 58 | 59 | guard first.count == second.count else { return } 60 | 61 | var tabs = "" 62 | for _ in 0...tabsSize { 63 | tabs += "\t" 64 | } 65 | 66 | let paragraph = NSMutableParagraphStyle() 67 | paragraph.alignment = .left 68 | for tabStop in paragraph.tabStops { 69 | paragraph.removeTabStop(tabStop) 70 | } 71 | if (!isHorizontal) { 72 | paragraph.addTabStop(NSTextTab(textAlignment: .right, location: 150.0, options: [:] )) 73 | } 74 | 75 | let text = NSMutableAttributedString() 76 | let leftAttributes = [ 77 | NSAttributedString.Key.foregroundColor: firstColor, 78 | NSAttributedString.Key.paragraphStyle: paragraph 79 | ] 80 | let rightAttributes = [ 81 | NSAttributedString.Key.foregroundColor: secondOther, 82 | NSAttributedString.Key.paragraphStyle: paragraph 83 | ] 84 | 85 | first.enumerated().forEach { (index, elem) in 86 | 87 | text.append(NSAttributedString(string: elem, attributes: leftAttributes)) 88 | text.append(NSAttributedString(string: "\t\(second[index])\t\(tabs)", attributes: rightAttributes)) 89 | if !isHorizontal, index != first.count - 1 { 90 | text.append(NSAttributedString(string: "\n")) 91 | } 92 | } 93 | 94 | self.attributedText = text 95 | 96 | } 97 | 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AALinedLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AALinedLabel.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// AALinedLabel 28 | open class AALinedLabel: UIView { 29 | 30 | @IBInspectable var lineInsideOffset: CGFloat = 20 31 | @IBInspectable var lineOutsideOffset: CGFloat = 20 32 | @IBInspectable var lineHeight: CGFloat = 1 33 | @IBInspectable var lineColor: UIColor = .gray 34 | @IBInspectable var labelText: String = "Some Label" { 35 | didSet { 36 | label.text = labelText 37 | } 38 | } 39 | 40 | public let label = UILabel() 41 | 42 | //MARK: - init 43 | override init(frame: CGRect) { 44 | super.init(frame: frame) 45 | initLabel() 46 | } 47 | required public init?(coder aDecoder: NSCoder) { 48 | super.init(coder: aDecoder) 49 | initLabel() 50 | } 51 | convenience init() {self.init(frame: CGRect.zero)} 52 | 53 | func initLabel() { 54 | label.text = labelText 55 | label.textAlignment = .center 56 | label.translatesAutoresizingMaskIntoConstraints = false 57 | 58 | let top = NSLayoutConstraint(item: self, attribute: .top, relatedBy: .equal, toItem: label, attribute: .top, multiplier: 1, constant: 0) 59 | let bot = NSLayoutConstraint(item: self, attribute: .bottom, relatedBy: .equal, toItem: label, attribute: .bottom, multiplier: 1, constant: 0) 60 | let lead = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .lessThanOrEqual, toItem: label, attribute: .leading, multiplier: 1, constant: 0) 61 | let trail = NSLayoutConstraint(item: self, attribute: .trailing, relatedBy: .greaterThanOrEqual, toItem: label, attribute: .trailing, multiplier: 1, constant: 0) 62 | let centerX = NSLayoutConstraint(item: self, attribute: .centerX, relatedBy: .equal, toItem: label, attribute: .centerX, multiplier: 1, constant: 0) 63 | 64 | addSubview(label) 65 | addConstraints([top, bot, lead, trail, centerX]) 66 | isOpaque = false 67 | } 68 | 69 | override open func draw(_ rect: CGRect) { 70 | let lineWidth = label.frame.minX - rect.minX - lineInsideOffset - lineOutsideOffset 71 | if lineWidth <= 0 {return} 72 | 73 | let lineLeft = UIBezierPath(rect: CGRect(x: rect.minX + lineOutsideOffset, y: rect.midY, width: lineWidth, height: 1)) 74 | let lineRight = UIBezierPath(rect: CGRect(x: label.frame.maxX + lineInsideOffset, y: rect.midY, width: lineWidth, height: 1)) 75 | 76 | lineLeft.lineWidth = lineHeight 77 | lineColor.set() 78 | lineLeft.stroke() 79 | 80 | lineRight.lineWidth = lineHeight 81 | lineColor.set() 82 | lineRight.stroke() 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AAPaddingLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAPaddingLabel.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/04/04. 6 | // 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 | @IBDesignable 27 | open class AAPaddingLabel: UILabel { 28 | 29 | @IBInspectable open var topInset: CGFloat = 0.0 30 | @IBInspectable open var leftInset: CGFloat = 0.0 31 | @IBInspectable open var bottomInset: CGFloat = 0.0 32 | @IBInspectable open var rightInset: CGFloat = 0.0 33 | 34 | var insets: UIEdgeInsets { 35 | get { .init(top: topInset, left: leftInset, bottom: bottomInset, right: rightInset) } 36 | set { 37 | topInset = newValue.top 38 | leftInset = newValue.left 39 | bottomInset = newValue.bottom 40 | rightInset = newValue.right 41 | } 42 | } 43 | 44 | open override func sizeThatFits(_ size: CGSize) -> CGSize { 45 | var adjSize = super.sizeThatFits(size) 46 | adjSize.width += leftInset + rightInset 47 | adjSize.height += topInset + bottomInset 48 | return adjSize 49 | } 50 | 51 | open override var intrinsicContentSize: CGSize { 52 | let systemContentSize = super.intrinsicContentSize 53 | let adjustSize = CGSize(width: systemContentSize.width + leftInset + rightInset, height: systemContentSize.height + topInset + bottomInset) 54 | if adjustSize.width > preferredMaxLayoutWidth && preferredMaxLayoutWidth != 0 { 55 | let constraintSize = CGSize(width: bounds.width - (leftInset + rightInset), height: .greatestFiniteMagnitude) 56 | let newSize = super.sizeThatFits(constraintSize) 57 | return CGSize(width: systemContentSize.width, height: ceil(newSize.height) + topInset + bottomInset) 58 | } else { 59 | return adjustSize 60 | } 61 | } 62 | 63 | open override func drawText(in rect: CGRect) { 64 | super.drawText(in: rect.inset(by: insets)) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AATimerLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AATimerLabel.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// AATimerLabel 28 | open class AATimerLabel: UILabel { 29 | 30 | public var seconds: Double = 60 31 | var isTimerReverse: Bool = false 32 | var isTimerRunning: Bool = false 33 | var resumeTapped: Bool = false 34 | public var timer = Timer() 35 | 36 | public func startTimer(_ seconds: Double, _ reverse: Bool) { 37 | isTimerReverse = reverse 38 | if isTimerRunning == false { 39 | self.seconds = seconds 40 | runTimer() 41 | } 42 | } 43 | 44 | private func runTimer() { 45 | timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: (#selector(updateTimer)), userInfo: nil, repeats: true) 46 | isTimerRunning = true 47 | } 48 | 49 | public func resetTimer(_ seconds: Double) { 50 | timer.invalidate() 51 | self.seconds = seconds 52 | self.text = seconds.aa_secondsTommss 53 | isTimerRunning = false 54 | } 55 | 56 | public func stopTimer() { 57 | timer.invalidate() 58 | self.text = "00:00" 59 | isTimerRunning = false 60 | } 61 | 62 | @objc private func updateTimer() { 63 | if isTimerReverse { 64 | if seconds < 1 { 65 | timer.invalidate() 66 | //Send alert to indicate time's up. 67 | } else { 68 | seconds -= 1 69 | self.text = seconds.aa_secondsTommss 70 | } 71 | } else { 72 | seconds += 1 73 | self.text = seconds.aa_secondsTommss 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UILabel/Module+AAVerticalAlignLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAVerticalAlignLabel.swift 3 | // AAExtensions 4 | // 5 | // Created by Ahsan Ali on 30/05/2019. 6 | // 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 | @IBDesignable 27 | open class AAVerticalAlignLabel: UILabel { 28 | 29 | @IBInspectable var alignmentCode: Int = 0 { 30 | didSet { applyAlignmentCode() } 31 | } 32 | 33 | func applyAlignmentCode() { 34 | switch alignmentCode { 35 | case 0: verticalAlignment = .top 36 | case 1: verticalAlignment = .topcenter 37 | case 2: verticalAlignment = .middle 38 | case 3: verticalAlignment = .bottom 39 | default: break 40 | } 41 | } 42 | 43 | override open func awakeFromNib() { 44 | super.awakeFromNib() 45 | self.applyAlignmentCode() 46 | } 47 | 48 | override init(frame: CGRect) { 49 | super.init(frame: frame) 50 | sharedInit() 51 | } 52 | 53 | required public init?(coder aDecoder: NSCoder) { 54 | super.init(coder: aDecoder) 55 | sharedInit() 56 | } 57 | 58 | override open func prepareForInterfaceBuilder() { 59 | super.prepareForInterfaceBuilder() 60 | sharedInit() 61 | self.applyAlignmentCode() 62 | } 63 | 64 | func sharedInit() { } 65 | 66 | enum VerticalAlignment { 67 | case top 68 | case topcenter 69 | case middle 70 | case bottom 71 | } 72 | 73 | var verticalAlignment : VerticalAlignment = .top { 74 | didSet { setNeedsDisplay() } 75 | } 76 | 77 | override open func textRect(forBounds bounds: CGRect, limitedToNumberOfLines: Int) -> CGRect { 78 | let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: limitedToNumberOfLines) 79 | 80 | if #available(iOS 9.0, *) { 81 | if UIView.userInterfaceLayoutDirection(for: .unspecified) == .rightToLeft { 82 | switch verticalAlignment { 83 | case .top: 84 | return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) 85 | case .topcenter: 86 | return CGRect(x: self.bounds.size.width - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height) 87 | case .middle: 88 | return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) 89 | case .bottom: 90 | return CGRect(x: self.bounds.size.width - rect.size.width, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) 91 | } 92 | } else { 93 | switch verticalAlignment { 94 | case .top: 95 | return CGRect(x: bounds.origin.x, y: bounds.origin.y, width: rect.size.width, height: rect.size.height) 96 | case .topcenter: 97 | return CGRect(x: (self.bounds.size.width / 2 ) - (rect.size.width / 2), y: bounds.origin.y, width: rect.size.width, height: rect.size.height) 98 | case .middle: 99 | return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height) / 2, width: rect.size.width, height: rect.size.height) 100 | case .bottom: 101 | return CGRect(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - rect.size.height), width: rect.size.width, height: rect.size.height) 102 | } 103 | } 104 | } else { 105 | // Fallback on earlier versions 106 | return rect 107 | } 108 | } 109 | 110 | override open func drawText(in rect: CGRect) { 111 | let r = self.textRect(forBounds: rect, limitedToNumberOfLines: self.numberOfLines) 112 | super.drawText(in: r) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UITextView/Module+AAPlaceholderTextView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAPlaceholderTextView.swift 3 | // AAExtensions 4 | // 5 | // Created by MacBook Pro on 17/03/2019. 6 | // 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 | /// AAPlaceholderTextView 28 | open class AAPlaceholderTextView: UITextView { 29 | 30 | @IBInspectable open var placeholderColor: UIColor = .lightGray 31 | @IBInspectable open var placeholderText: String = "" 32 | 33 | override open var font: UIFont? { 34 | didSet { 35 | setNeedsDisplay() 36 | } 37 | } 38 | 39 | override open var contentInset: UIEdgeInsets { 40 | didSet { 41 | setNeedsDisplay() 42 | } 43 | } 44 | 45 | override open var textAlignment: NSTextAlignment { 46 | didSet { 47 | setNeedsDisplay() 48 | } 49 | } 50 | 51 | override open var text: String? { 52 | didSet { 53 | setNeedsDisplay() 54 | } 55 | } 56 | 57 | override open var attributedText: NSAttributedString? { 58 | didSet { 59 | setNeedsDisplay() 60 | } 61 | } 62 | 63 | required public init?(coder aDecoder: NSCoder) { 64 | super.init(coder: aDecoder) 65 | setUp() 66 | } 67 | 68 | override init(frame: CGRect, textContainer: NSTextContainer?) { 69 | super.init(frame: frame, textContainer: textContainer) 70 | } 71 | 72 | private func setUp() { 73 | NotificationCenter.default.addObserver(self, 74 | selector: #selector(self.textChanged(notification:)), 75 | name: Notification.Name("UITextViewTextDidChangeNotification"), 76 | object: nil) 77 | } 78 | 79 | @objc func textChanged(notification: NSNotification) { 80 | setNeedsDisplay() 81 | } 82 | 83 | func placeholderRectForBounds(bounds: CGRect) -> CGRect { 84 | var x = contentInset.left + 4.0 85 | var y = contentInset.top + 9.0 86 | let w = frame.size.width - contentInset.left - contentInset.right - 16.0 87 | let h = frame.size.height - contentInset.top - contentInset.bottom - 16.0 88 | 89 | if let style = self.typingAttributes[NSAttributedString.Key.paragraphStyle] as? NSParagraphStyle { 90 | x += style.headIndent 91 | y += style.firstLineHeadIndent 92 | } 93 | return CGRect(x: x, y: y, width: w, height: h) 94 | } 95 | 96 | override open func draw(_ rect: CGRect) { 97 | if text!.isEmpty && !placeholderText.isEmpty { 98 | let paragraphStyle = NSMutableParagraphStyle() 99 | paragraphStyle.alignment = textAlignment 100 | let attributes: [NSAttributedString.Key: Any] = [ 101 | NSAttributedString.Key(rawValue: NSAttributedString.Key.font.rawValue) : font!, 102 | NSAttributedString.Key(rawValue: NSAttributedString.Key.foregroundColor.rawValue) : placeholderColor, 103 | NSAttributedString.Key(rawValue: NSAttributedString.Key.paragraphStyle.rawValue) : paragraphStyle] 104 | 105 | placeholderText.draw(in: placeholderRectForBounds(bounds: bounds), withAttributes: attributes) 106 | } 107 | super.draw(rect) 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UIView/Module+AABorderLinesView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AABorderLinesView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | open class AABorderLinesView: UIView { 28 | 29 | @IBInspectable open var paddingX: CGFloat = 0 30 | @IBInspectable open var paddingY: CGFloat = 0 31 | @IBInspectable open var lineWidth: CGFloat = 1 32 | @IBInspectable open var leftSide: UIColor? = nil 33 | @IBInspectable open var rightSide: UIColor? = nil 34 | @IBInspectable open var topSide: UIColor? = nil 35 | @IBInspectable open var bottomSide: UIColor? = nil 36 | 37 | var isInterfaceBuilder: Bool = false 38 | 39 | override init(frame: CGRect) { 40 | super.init(frame: frame) 41 | sharedInit() 42 | } 43 | 44 | required public init?(coder aDecoder: NSCoder) { 45 | super.init(coder: aDecoder) 46 | sharedInit() 47 | } 48 | 49 | override open func prepareForInterfaceBuilder() { 50 | super.prepareForInterfaceBuilder() 51 | self.isInterfaceBuilder = true 52 | sharedInit() 53 | } 54 | 55 | override open func awakeFromNib() { 56 | super.awakeFromNib() 57 | } 58 | 59 | func sharedInit() { } 60 | 61 | override open func draw(_ rect: CGRect) { 62 | super.draw(rect) 63 | 64 | if !isInterfaceBuilder { 65 | if let side = topSide { 66 | aa.addTopBorderWithColor(color: side, height: lineWidth, paddingX: paddingX, paddingY: paddingY) 67 | } else if let side = leftSide { 68 | aa.addLeftBorderWithColor(color: side, width: lineWidth, paddingX: paddingX, paddingY: paddingY) 69 | } else if let side = rightSide { 70 | aa.addRightBorderWithColor(color: side, width: lineWidth, paddingX: paddingX, paddingY: paddingY) 71 | } else if let side = bottomSide { 72 | aa.addBottomBorderWithColor(color: side, height: lineWidth, paddingX: paddingX, paddingY: paddingY) 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Module+UIView/Module+AAGradientView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+AAGradientView.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | @available(iOS 9.0, *) 27 | public struct AAGradientModel { 28 | public let colors: [UIColor] 29 | public let startPoint, endPoint: AAPoint 30 | public let locations: [NSNumber] 31 | 32 | public init(colors: [UIColor], startPoint: AAPoint, endPoint: AAPoint, locations: [NSNumber]) { 33 | self.colors = colors 34 | self.locations = locations 35 | self.startPoint = startPoint 36 | self.endPoint = endPoint 37 | } 38 | } 39 | 40 | @available(iOS 9.0, *) 41 | public class AAGradientView: UIView { 42 | 43 | weak var gradientLayer: CAGradientLayer! 44 | 45 | var model: AAGradientModel! 46 | 47 | public convenience init(_ model: AAGradientModel) { 48 | 49 | self.init(frame: .zero) 50 | self.model = model 51 | let gradientLayer = CAGradientLayer() 52 | gradientLayer.name = "AAGradientView" 53 | gradientLayer.frame = frame 54 | layer.addSublayer(gradientLayer) 55 | self.gradientLayer = gradientLayer 56 | set() 57 | backgroundColor = .clear 58 | } 59 | 60 | func set() { 61 | 62 | gradientLayer.colors = model.colors.map { $0.cgColor } 63 | gradientLayer.startPoint = model.startPoint.point 64 | gradientLayer.endPoint = model.endPoint.point 65 | gradientLayer.locations = model.locations 66 | } 67 | 68 | open func setupConstraints() { 69 | guard let parentView = superview else { return } 70 | translatesAutoresizingMaskIntoConstraints = false 71 | topAnchor.constraint(equalTo: parentView.topAnchor).isActive = true 72 | leftAnchor.constraint(equalTo: parentView.leftAnchor).isActive = true 73 | parentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true 74 | parentView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true 75 | } 76 | 77 | public override func layoutSubviews() { 78 | super.layoutSubviews() 79 | guard let gradientLayer = gradientLayer else { return } 80 | gradientLayer.frame = frame 81 | superview?.addSubview(self) 82 | superview?.sendSubviewToBack(self) 83 | } 84 | } 85 | 86 | 87 | 88 | // MARK: - UINavigationController 89 | public extension AA where Base: UIViewController { 90 | 91 | @available(iOS 9.0, *) 92 | func setGradientNavigation(_ model: AAGradientModel) { 93 | guard let backgroundView = base.navigationController?.navigationBar.value(forKey: "backgroundView") as? UIView else { 94 | return 95 | } 96 | 97 | guard let gradientView = backgroundView.subviews.first(where: { $0 is AAGradientView }) as? AAGradientView else { 98 | let gradientView = AAGradientView(model) 99 | backgroundView.addSubview(gradientView) 100 | gradientView.setupConstraints() 101 | return 102 | } 103 | 104 | gradientView.set() 105 | } 106 | 107 | 108 | } 109 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Modules/Modules+UIImageView/Module+LoadImage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Module+LoadImage.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2021/04/04. 6 | // 7 | 8 | /// Global cache for downloaded UIImage 9 | fileprivate let ImageCache = NSCache() 10 | 11 | public extension AA where Base: UIImageView { 12 | 13 | /// Fetches the UIImage from the network or cache 14 | /// 15 | /// - Parameters: 16 | /// - urlString: Request URL 17 | /// - placeholder: placeholder 18 | @discardableResult 19 | func loadImage(withUrl urlString : String, placeholder: UIImage?) -> URLSessionDataTask? { 20 | guard let url = URL(string: urlString) else { return nil } 21 | 22 | if let placeholder = placeholder { base.image = placeholder } 23 | 24 | // check cached image 25 | if let cachedImage = ImageCache.object(forKey: urlString as NSString) as? UIImage { 26 | base.image = cachedImage 27 | return nil 28 | } 29 | 30 | // if not, download image from url 31 | let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, response, error) in 32 | if error != nil { 33 | print(error!) 34 | return 35 | } 36 | 37 | DispatchQueue.main.async { 38 | if let image = UIImage(data: data!) { 39 | ImageCache.setObject(image, forKey: urlString as NSString) 40 | base.image = image 41 | } 42 | } 43 | 44 | }) 45 | 46 | task.resume() 47 | return task 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Shared/AA_Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AA_Constants.swift 3 | // AAExtensions 4 | // 5 | // Created by M. Ahsan Ali on 14/03/2019. 6 | // 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 | /// Constant variables 28 | var AA_AssociationKeyMaxLength: Int = 0 29 | var AA_AssociationKeyAnyCallback: Int = 0 30 | var AA_AssociationKeyAnyData: Int = 1 31 | var AA_AssociationKeyAnyDataWithCallback: Int = 2 32 | 33 | let AA_TAG = "AAExtensions:- " 34 | 35 | /// Contant typealias 36 | public typealias AACompletionVoid = (() -> ()) 37 | public typealias AACompletionAny = ((Any) -> ()) 38 | public typealias AAKeyValue = [String: Any] 39 | 40 | /// Constant computations 41 | public var aa_rootVC: UIViewController 42 | { UIApplication.shared.windows.filter {$0.isKeyWindow}.first!.rootViewController! } 43 | 44 | public var aa_topVC: UIViewController { aa_rootVC.aa.topViewController } 45 | 46 | public let AAHelper = { return AA_Helper.shared }() 47 | 48 | // MARK: - Extenders and default strings 49 | 50 | /* Can extend 51 | extension String.AARegularExpressions { 52 | static var test = "" 53 | } 54 | if regex.rawValue == AARegularExpressions.test { } 55 | */ 56 | 57 | /// AARegularExpressions 58 | public enum AARegularExpressions: String { 59 | case phone = "^\\s*(?:\\+?(\\d{1,3}))?([-. (]*(\\d{3})[-. )]*)?((\\d{3})[-. ]*(\\d{2,4})(?:[-.x ]*(\\d+))?)\\s*$" 60 | case email = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" 61 | case url = "((www\\.|(http|https)+\\:\\/\\/)?[_a-z0-9-]+\\.[a-z0-9\\/__:@=.+?,##%&~-]*[^.|\'|\\# |!|\\(|?|,| |>|<|;|\\)])" 62 | case alphanumeric = "[\\d[A-Za-z]]+" 63 | case alpha = "[a-zA-Z]+" 64 | case base64 = "(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?" 65 | case hex_color = "#?([0-9A-F]{3}|[0-9A-F]{6})" 66 | case hexa_decimal = "[0-9A-F]+" 67 | case ascii = "[\\x00-\\x7F]+" 68 | case numeric = "[-+]?[0-9]+" 69 | case float = "([\\+-]?\\d+)?\\.?\\d*([eE][\\+-]\\d+)?" 70 | case creditcard = "(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])case [0-9]{11}|(?:2131|1800|35\\d{3})\\d{11})" 71 | } 72 | 73 | 74 | 75 | /// AADateFormatters 76 | public enum AADateFormatters: String { 77 | case format1 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" // 2019-06-15T08:40:19+000000 78 | case format2 = "EEEE, MMM d, yyyy" // Saturday, Jun 15, 2019 79 | case format3 = "MM/dd/yyyy" // 06/15/2019 80 | case format4 = "MM-dd-yyyy HH:mm" // 06-15-2019 08:40 81 | case format5 = "MMM d, h:mm a" // Jun 15, 8:40 AM 82 | case format6 = "MMMM yyyy" // June 2019 83 | case format7 = "MMM d, yyyy" // Jun 15, 2019 84 | case format8 = "E, d MMM yyyy HH:mm:ss Z" // Sat, 15 Jun 2019 08:40:19 +0000 85 | case format9 = "yyyy-MM-dd'T'HH:mm:ssZ" // 2019-06-15T08:40:19+0000 86 | case format10 = "dd.MM.yy" // 15.06.19 87 | case format11 = "HH:mm:ss.SSS" // 08:40:19.200 88 | case format12 = "yyyy-MM-dd" // 2019-15-06 89 | case format13 = "dd MMM, yyyy" // 06 June, 2019 90 | case format14 = "yyyy-MM-dd HH:mm:ss" // 2019-06-16 08:47:45 91 | case format15 = "MMM dd : HH:mm a" // Jun 16 : 08:47 AM 92 | case format16 = "hh:mm a" // 12:00 AM 93 | 94 | } 95 | 96 | /// AAPoint 97 | public enum AAPoint { 98 | case topRight, topLeft 99 | case bottomRight, bottomLeft 100 | case custom(point: CGPoint) 101 | 102 | public var point: CGPoint { 103 | switch self { 104 | case .topRight: return CGPoint(x: 1, y: 0) 105 | case .topLeft: return CGPoint(x: 0, y: 0) 106 | case .bottomRight: return CGPoint(x: 1, y: 1) 107 | case .bottomLeft: return CGPoint(x: 0, y: 1) 108 | case .custom(let point): return point 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /AAExtensions/Classes/Shared/AA_ExtensionProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AA_ExtensionProvider.swift 3 | // AAExtensions 4 | // 5 | // Created by Muhammad Ahsan Ali on 2020/05/03. 6 | // 7 | 8 | 9 | public protocol AAExtensionsProvider: AnyObject { 10 | associatedtype CompatibleType 11 | var aa: CompatibleType { get } 12 | } 13 | 14 | extension AAExtensionsProvider { 15 | /// A proxy which hosts reactive extensions for `self`. 16 | public var aa: AA { AA(self) } 17 | } 18 | 19 | public struct AA { 20 | public let base: Base 21 | fileprivate init(_ base: Base) { self.base = base } 22 | } 23 | 24 | extension UIView: AAExtensionsProvider {} 25 | extension UIImage: AAExtensionsProvider {} 26 | extension UIFont: AAExtensionsProvider {} 27 | extension UIViewController: AAExtensionsProvider {} 28 | -------------------------------------------------------------------------------- /Example/AAExtensions.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/AAExtensions.xcodeproj/xcshareddata/xcschemes/AAExtensions-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 67 | 68 | 78 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 99 | 105 | 106 | 107 | 108 | 110 | 111 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /Example/AAExtensions.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/AAExtensions.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/AAExtensions/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AAExtensions 4 | // 5 | // Created by EngrAhsanAli on 03/14/2019. 6 | // Copyright (c) 2019 EngrAhsanAli. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. 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 inactive 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 | -------------------------------------------------------------------------------- /Example/AAExtensions/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 27 | 28 | 29 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AA.imageset/17049477.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AA.imageset/17049477.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AA.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "17049477.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "57x57", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-57x57@1x.png", 49 | "scale" : "1x" 50 | }, 51 | { 52 | "size" : "57x57", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-57x57@2x.png", 55 | "scale" : "2x" 56 | }, 57 | { 58 | "size" : "60x60", 59 | "idiom" : "iphone", 60 | "filename" : "Icon-App-60x60@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "60x60", 65 | "idiom" : "iphone", 66 | "filename" : "Icon-App-60x60@3x.png", 67 | "scale" : "3x" 68 | }, 69 | { 70 | "size" : "20x20", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-20x20@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "20x20", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-20x20@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "29x29", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-29x29@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "29x29", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-29x29@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "40x40", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-40x40@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "40x40", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-40x40@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "50x50", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-Small-50x50@1x.png", 109 | "scale" : "1x" 110 | }, 111 | { 112 | "size" : "50x50", 113 | "idiom" : "ipad", 114 | "filename" : "Icon-Small-50x50@2x.png", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "72x72", 119 | "idiom" : "ipad", 120 | "filename" : "Icon-App-72x72@1x.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "72x72", 125 | "idiom" : "ipad", 126 | "filename" : "Icon-App-72x72@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "76x76", 131 | "idiom" : "ipad", 132 | "filename" : "Icon-App-76x76@1x.png", 133 | "scale" : "1x" 134 | }, 135 | { 136 | "size" : "76x76", 137 | "idiom" : "ipad", 138 | "filename" : "Icon-App-76x76@2x.png", 139 | "scale" : "2x" 140 | }, 141 | { 142 | "size" : "83.5x83.5", 143 | "idiom" : "ipad", 144 | "filename" : "Icon-App-83.5x83.5@2x.png", 145 | "scale" : "2x" 146 | }, 147 | { 148 | "idiom" : "ios-marketing", 149 | "size" : "1024x1024", 150 | "scale" : "1x" 151 | } 152 | ], 153 | "info" : { 154 | "version" : 1, 155 | "author" : "xcode" 156 | } 157 | } -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-Small-50x50@1x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EngrAhsanAli/AAExtensions/848c12ab7a97ec69f26d9d3e53e80733f060511d/Example/AAExtensions/Images.xcassets/AppIcon.appiconset/Icon-Small-50x50@2x.png -------------------------------------------------------------------------------- /Example/AAExtensions/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/AAExtensions/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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Example/AAExtensions/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AAExtensions 4 | // 5 | // Created by EngrAhsanAli on 03/14/2019. 6 | // Copyright (c) 2019 EngrAhsanAli. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AAExtensions 11 | 12 | class ViewController: UIViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | // Do any additional setup after loading the view, typically from a nib. 17 | 18 | 19 | self.view.aa.onTap { 20 | self.aa_callBack?("Some Value") 21 | } 22 | 23 | self.aa_callBack = { 24 | print($0) 25 | } 26 | 27 | 28 | 29 | 30 | } 31 | 32 | override func didReceiveMemoryWarning() { 33 | super.didReceiveMemoryWarning() 34 | // Dispose of any resources that can be recreated. 35 | } 36 | 37 | override func viewDidAppear(_ animated: Bool) { 38 | 39 | let timeAgp = Date().aa_timeAgo(numericDates: true) 40 | print(timeAgp) 41 | } 42 | 43 | 44 | func aa_presentDocumentPicker() { 45 | let extensions = ".pdf,.jpeg,.png,.gif,.doc,.docx,.rtf,.txt,.odf,.xlsx,.ppt" 46 | 47 | // aa.presentDocumentPicker(extensions) { 48 | // print($0) 49 | // } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'AAExtensions_Example' do 4 | pod 'AAExtensions', :path => '../' 5 | 6 | target 'AAExtensions_Tests' do 7 | inherit! :search_paths 8 | 9 | 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AAExtensions (1.2.6) 3 | 4 | DEPENDENCIES: 5 | - AAExtensions (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | AAExtensions: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | AAExtensions: 65d710bc7119d88e1bb2717b4082e4296c08c505 13 | 14 | PODFILE CHECKSUM: 235bd8c022839c4e590529843756dc80cca0c96b 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/AAExtensions.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AAExtensions", 3 | "version": "1.2.6", 4 | "summary": "AAExtensions are a set of UI Extensions and Helper functions for iOS applications which is written in Swift 5.0", 5 | "description": "AAExtensions are a set of UI Extensions and Helper functions for iOS applications which is written in Swift 5.0.", 6 | "homepage": "https://github.com/EngrAhsanAli/AAExtensions", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "EngrAhsanAli": "hafiz.m.ahsan.ali@gmail.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/EngrAhsanAli/AAExtensions.git", 16 | "tag": "1.2.6" 17 | }, 18 | "platforms": { 19 | "ios": "9.0" 20 | }, 21 | "swift_versions": "5.0", 22 | "source_files": "AAExtensions/Classes/**/*", 23 | "swift_version": "5.0" 24 | } 25 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AAExtensions (1.2.6) 3 | 4 | DEPENDENCIES: 5 | - AAExtensions (from `../`) 6 | 7 | EXTERNAL SOURCES: 8 | AAExtensions: 9 | :path: "../" 10 | 11 | SPEC CHECKSUMS: 12 | AAExtensions: 65d710bc7119d88e1bb2717b4082e4296c08c505 13 | 14 | PODFILE CHECKSUM: 235bd8c022839c4e590529843756dc80cca0c96b 15 | 16 | COCOAPODS: 1.10.1 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions-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.2.6 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_AAExtensions : NSObject 3 | @end 4 | @implementation PodsDummy_AAExtensions 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double AAExtensionsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char AAExtensionsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 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 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions.modulemap: -------------------------------------------------------------------------------- 1 | framework module AAExtensions { 2 | umbrella header "AAExtensions-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 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 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | SKIP_INSTALL = YES 12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/AAExtensions/AAExtensions.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example-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 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## AAExtensions 5 | 6 | Copyright (c) 2019 EngrAhsanAli 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 | Generated by CocoaPods - https://cocoapods.org 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example-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) 2019 EngrAhsanAli <hafiz.m.ahsan.ali@gmail.com> 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | 37 | License 38 | MIT 39 | Title 40 | AAExtensions 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | Generated by CocoaPods - https://cocoapods.org 47 | Title 48 | 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | StringsTable 54 | Acknowledgements 55 | Title 56 | Acknowledgements 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_AAExtensions_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_AAExtensions_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_AAExtensions_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_AAExtensions_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions/AAExtensions.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "AAExtensions" 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_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_AAExtensions_Example { 2 | umbrella header "Pods-AAExtensions_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Example/Pods-AAExtensions_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions/AAExtensions.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "AAExtensions" 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_PODFILE_DIR_PATH = ${SRCROOT}/. 12 | PODS_ROOT = ${SRCROOT}/Pods 13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 15 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests-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 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_AAExtensions_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_AAExtensions_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_AAExtensions_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_AAExtensions_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions/AAExtensions.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "AAExtensions" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_AAExtensions_Tests { 2 | umbrella header "Pods-AAExtensions_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-AAExtensions_Tests/Pods-AAExtensions_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AAExtensions/AAExtensions.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "AAExtensions" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 12 | -------------------------------------------------------------------------------- /Example/Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Example/Tests/Tests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import AAExtensions 3 | 4 | class Tests: XCTestCase { 5 | 6 | override func setUp() { 7 | super.setUp() 8 | // Put setup code here. This method is called before the invocation of each test method in the class. 9 | } 10 | 11 | override func tearDown() { 12 | // Put teardown code here. This method is called after the invocation of each test method in the class. 13 | super.tearDown() 14 | } 15 | 16 | func testExample() { 17 | // This is an example of a functional test case. 18 | XCTAssert(true, "Pass") 19 | } 20 | 21 | func testPerformanceExample() { 22 | // This is an example of a performance test case. 23 | self.measure() { 24 | // Put the code you want to measure the time of here. 25 | } 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 EngrAhsanAli 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------