├── .gitignore ├── .swiftpm └── xcode │ └── package.xcworkspace │ └── contents.xcworkspacedata ├── .travis.yml ├── AnyFormatKit.h ├── AnyFormatKit.podspec ├── AnyFormatKit.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── AnyFormatKit.xcscheme ├── AnyFormatKit.xcworkspace └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Assets ├── anyformatkit.jpeg ├── example_card_number.gif ├── example_phone_number.gif ├── example_placeholder_phone_number.gif └── example_sum.gif ├── BundleFiles └── Info.plist ├── Documentation ├── AnyFormatKit 0.2.0 MigrationGuide.md ├── AnyFormatKit 1.0.0 MigrationGuide.md └── AnyFormatKit 2.4.0 MigrationGuide.md ├── Example ├── CocoapodsExample │ ├── Podfile │ ├── Podfile.lock │ ├── Pods │ │ ├── Local Podspecs │ │ │ └── AnyFormatKit.podspec.json │ │ ├── Manifest.lock │ │ ├── Pods.xcodeproj │ │ │ └── project.pbxproj │ │ ├── SnapKit │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── Source │ │ │ │ ├── Constraint.swift │ │ │ │ ├── ConstraintAttributes.swift │ │ │ │ ├── ConstraintConfig.swift │ │ │ │ ├── ConstraintConstantTarget.swift │ │ │ │ ├── ConstraintDSL.swift │ │ │ │ ├── ConstraintDescription.swift │ │ │ │ ├── ConstraintInsetTarget.swift │ │ │ │ ├── ConstraintInsets.swift │ │ │ │ ├── ConstraintItem.swift │ │ │ │ ├── ConstraintLayoutGuide+Extensions.swift │ │ │ │ ├── ConstraintLayoutGuide.swift │ │ │ │ ├── ConstraintLayoutGuideDSL.swift │ │ │ │ ├── ConstraintLayoutSupport.swift │ │ │ │ ├── ConstraintLayoutSupportDSL.swift │ │ │ │ ├── ConstraintMaker.swift │ │ │ │ ├── ConstraintMakerEditable.swift │ │ │ │ ├── ConstraintMakerExtendable.swift │ │ │ │ ├── ConstraintMakerFinalizable.swift │ │ │ │ ├── ConstraintMakerPriortizable.swift │ │ │ │ ├── ConstraintMakerRelatable.swift │ │ │ │ ├── ConstraintMultiplierTarget.swift │ │ │ │ ├── ConstraintOffsetTarget.swift │ │ │ │ ├── ConstraintPriority.swift │ │ │ │ ├── ConstraintPriorityTarget.swift │ │ │ │ ├── ConstraintRelatableTarget.swift │ │ │ │ ├── ConstraintRelation.swift │ │ │ │ ├── ConstraintView+Extensions.swift │ │ │ │ ├── ConstraintView.swift │ │ │ │ ├── ConstraintViewDSL.swift │ │ │ │ ├── Debugging.swift │ │ │ │ ├── LayoutConstraint.swift │ │ │ │ ├── LayoutConstraintItem.swift │ │ │ │ ├── Typealiases.swift │ │ │ │ └── UILayoutSupport+Extensions.swift │ │ └── Target Support Files │ │ │ ├── AnyFormatKit │ │ │ ├── AnyFormatKit-Info.plist │ │ │ ├── AnyFormatKit-dummy.m │ │ │ ├── AnyFormatKit-prefix.pch │ │ │ ├── AnyFormatKit-umbrella.h │ │ │ ├── AnyFormatKit.debug.xcconfig │ │ │ ├── AnyFormatKit.modulemap │ │ │ └── AnyFormatKit.release.xcconfig │ │ │ ├── Pods-iOS Example │ │ │ ├── Pods-iOS Example-Info.plist │ │ │ ├── Pods-iOS Example-acknowledgements.markdown │ │ │ ├── Pods-iOS Example-acknowledgements.plist │ │ │ ├── Pods-iOS Example-dummy.m │ │ │ ├── Pods-iOS Example-frameworks.sh │ │ │ ├── Pods-iOS Example-umbrella.h │ │ │ ├── Pods-iOS Example.debug.xcconfig │ │ │ ├── Pods-iOS Example.modulemap │ │ │ └── Pods-iOS Example.release.xcconfig │ │ │ └── SnapKit │ │ │ ├── SnapKit-Info.plist │ │ │ ├── SnapKit-dummy.m │ │ │ ├── SnapKit-prefix.pch │ │ │ ├── SnapKit-umbrella.h │ │ │ ├── SnapKit.debug.xcconfig │ │ │ ├── SnapKit.modulemap │ │ │ └── SnapKit.release.xcconfig │ ├── iOS Example.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── UIKitExample.xcscheme │ │ │ └── iOS Example.xcscheme │ ├── iOS Example.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── iOS Example │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ │ ├── ExampleView.swift │ │ ├── ExampleViewController.swift │ │ ├── Helpers │ │ ├── CardInfoView.swift │ │ ├── InitView.swift │ │ ├── TitleTextFieldView.swift │ │ └── UIFont+Extension.swift │ │ └── Info.plist └── SPMExample │ ├── AnyFormatKitSPMExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved │ └── AnyFormatKitSPMExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── ExampleView.swift │ ├── ExampleViewController.swift │ ├── Helpers │ ├── CardInfoView.swift │ ├── InitView.swift │ ├── TitleTextFieldView.swift │ └── UIFont+Extension.swift │ ├── Info.plist │ └── SceneDelegate.swift ├── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── Source ├── Controllers │ ├── TextFieldControllers │ │ ├── TextFieldInputController.swift │ │ └── TextFieldStartInputController.swift │ └── TextViewControllers │ │ ├── TextViewInputController.swift │ │ └── TextViewStartInputController.swift ├── Extensions │ ├── String+Extension.swift │ ├── UITextField+Extension.swift │ └── UITextView+Extension.swift └── TextFormatter │ ├── DefaultFormatters │ ├── Formatters │ │ ├── DefaultTextFormatter.swift │ │ └── DefaultTextInputFormatter.swift │ └── Helpers │ │ ├── DefaultCaretPositionCorrector.swift │ │ └── DefaultRangeCalculator.swift │ ├── PlaceholderFormatters │ ├── Formatters │ │ ├── PlaceholderTextFormatter.swift │ │ └── PlaceholderTextInputFormatter.swift │ └── Helpers │ │ ├── PlaceholderCaretPositionCalculator.swift │ │ └── PlaceholderRangeCalculator.swift │ ├── SumFormatters │ ├── Formatters │ │ ├── SumTextFormatter.swift │ │ └── SumTextInputFormatter.swift │ └── Helpers │ │ ├── SumFormatParser.swift │ │ └── SumTextInputFormatterCaretPositionCalculator.swift │ └── TextFormatter │ ├── CaretPositioner.swift │ ├── FormattedTextValue.swift │ ├── TextFormatter.swift │ ├── TextInputFormatter.swift │ ├── TextNumberFormatter.swift │ ├── TextNumberUnformatter.swift │ └── TextUnformatter.swift ├── Tests ├── DefaultTextFormatterTests │ ├── DefaultTextFormatterTests.swift │ └── DefaultTextFormatterUnformatTests.swift ├── DefaultTextInputFormatterTests │ ├── Format │ │ └── DefaultTextInputFormatterFormatTests.swift │ ├── FormatInput │ │ ├── Delete │ │ │ └── DefaultTextInputFormatterDeleteTests.swift │ │ ├── Insert │ │ │ ├── AnyFormatKitTests.swift │ │ │ ├── DefaultTextInputFormatterEmojisInputTests.swift │ │ │ ├── DefaultTextInputFormatterInputTests.swift │ │ │ └── DefaultTextInputFormatterPhoneEmojisInputTests.swift │ │ └── Replace │ │ │ ├── DefaultTextInputFormatter1SymbolReplaceTests.swift │ │ │ ├── DefaultTextInputFormatter2SymbolsReplaceTests.swift │ │ │ └── DefaultTextInputFormatter3SymbolsReplace.swift │ └── Unformat │ │ └── DefaultTextInputUnformattingTests.swift ├── Info.plist ├── PlaceholderFormatterTests │ ├── PlaceholderFormatterFormattingTests.swift │ └── PlaceholderFormatterUnformattingTests.swift ├── PlaceholderTextInputFormatterTests │ ├── Format │ │ └── PlaceholderTextInputFormatterFormatTests.swift │ ├── FormatInput │ │ ├── Delete │ │ │ ├── PlaceholderTextInputFormatterDelete3SymbolsTests.swift │ │ │ └── PlaceholderTextInputFormatterErasingBy1SymbolTests.swift │ │ ├── Insert │ │ │ ├── PlaceholderTextInputFormatterEmojisInputTests.swift │ │ │ ├── PlaceholderTextInputFormatterInputTests.swift │ │ │ └── PlaceholderTextInputFormatterInsert3SymbolsTests.swift │ │ └── Replace │ │ │ └── PlaceholderTextInputFormatterReplace3SymbolsTests.swift │ └── Unformat │ │ └── PlaceholderTextInputUnformattingTests.swift ├── SumFormatTests │ ├── FormatParsingTests.swift │ ├── SumFormatParserTests.swift │ └── SumTextFormatterFormatParseTests.swift ├── SumTextFormatterTests │ └── SumTextFormatterFormatTests.swift └── SumTextInputFormatterTests │ ├── FormatInput │ ├── Simple │ │ ├── Format │ │ │ └── SumTextInputFormatterFormatTests.swift │ │ ├── FormatInput │ │ │ ├── Delete │ │ │ │ ├── SumTextInputFormatterDelete3SymbolsTests.swift │ │ │ │ ├── SumTextInputFormatterErasingBy1SymbolTests.swift │ │ │ │ └── SumTextInputFormatterSpaceGroupSeparatorDelete1SymbolsTests.swift │ │ │ ├── Insert │ │ │ │ ├── SumTextInputFormatterInput0Tests.swift │ │ │ │ ├── SumTextInputFormatterInputTests.swift │ │ │ │ └── SumTextInputFormatterInsert3Symbols.swift │ │ │ └── Replace │ │ │ │ └── SumTextInputFormatterReplace3SymbolsTests.swift │ │ └── Unformat │ │ │ ├── SumTextInputFormatterNumberUnformatTests.swift │ │ │ └── SumTextInputFormatterUnformatTests.swift │ ├── WithPrefix │ │ ├── 1SymbolPrefix │ │ │ ├── Delete │ │ │ │ ├── SumTextInputFormatterWithPrefixBy1SymbolErasingTests.swift │ │ │ │ └── SumTextInputFormatterWithPrefixDelete3SymbolsTests.swift │ │ │ ├── Insert │ │ │ │ ├── SumTextInputFormatterWithPrefixInputTests.swift │ │ │ │ └── SumTextInputtFormaterWithPrefix3SymbolnsertTests.swift │ │ │ └── Replace │ │ │ │ └── SumTextInputFormatterWithPrefix3SymbolsReplaceTests.swift │ │ └── 2SymbolsPrefix │ │ │ ├── Delete │ │ │ ├── SumTextInputFormatterWith2SymbolsPrefixBy1SymbolErasingTests.swift │ │ │ └── SumTextInputFormatterWith2SymbolsPrefixDelete3SymbolsTests.swift │ │ │ └── Insert │ │ │ └── SumTextInputFormatterWith2SymbolsPrefixInputTests.swift │ └── WithSuffix │ │ ├── 1SymbolSuffix │ │ ├── Delete │ │ │ ├── SumTextInputFormatterWithSimilarCharactersInSuffixAndGroupSeparatorDelete1SymbolTests.swift │ │ │ ├── SumTextInputFormatterWithSuffixDelete1SymbolTests.swift │ │ │ ├── SumTextInputFormatterWithSuffixDelete2SymbolsTests.swift │ │ │ └── SumTextInputFormatterWithSuffixDelete3SymbolsTests.swift │ │ ├── Insert │ │ │ ├── SumTextInputFormatterWithSuffixInput0Tests.swift │ │ │ ├── SumTextInputFormatterWithSuffixInputTests.swift │ │ │ └── SumTextInputFormatterWithSuffixInsert2SymbolsTests.swift │ │ └── Replace │ │ │ ├── SumTextInputFormatterWithSuffixReplace1SymbolTests.swift │ │ │ ├── SumTextInputFormatterWithSuffixReplace2SymbolsTests.swift │ │ │ ├── SumTextInputFormatterWithSuffixReplace3SymbolsTests.swift │ │ │ └── SumTextInputFormatterWithSuffixReplaceWith0Tests.swift │ │ └── 2SymbolSuffix │ │ ├── Delete │ │ ├── SumTextInputFormatterWith2SymbolsSuffixBy1SymbolErasingTests.swift │ │ └── SumTextInputFormatterWith2SymbolsSuffixDelete3SymbolsTests.swift │ │ └── Insert │ │ ├── SumTextInputFormatterWith2SymbolsSuffixBy1SymbolInputTests.swift │ │ └── SumTextInputFormatterWith2SymbolsSuffixInsert2SymbolsTests.swift │ └── FormatParse │ └── SumTextInputFormatterFormatParseTests.swift ├── run-tests.sh └── update_version.rb /.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 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | # Pods/ 34 | AnyFormatKit.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist 35 | -------------------------------------------------------------------------------- /.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | osx_image: xcode11.3 3 | language: swift 4 | os: osx 5 | 6 | xcode_workspace: AnyFormatKit.xcworkspace 7 | xcode_scheme: 8 | - AnyFormatKit 9 | - AnyFormatKitTests 10 | - iOS Example 11 | 12 | branches: 13 | only: 14 | - master 15 | - develop 16 | 17 | script: ./run-tests.sh 18 | 19 | notifications: 20 | email: 21 | recipients: 22 | - luximetr.notification@gmail.com 23 | on_success: always 24 | on_failure: always -------------------------------------------------------------------------------- /AnyFormatKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // AnyFormatKit.h 3 | // AnyFormatKit 4 | // 5 | // Created by BRANDERSTUDIO on 01.11.2017. 6 | // Copyright © 2017 BRANDERSTUDIO. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for AnyFormatKit. 12 | FOUNDATION_EXPORT double AnyFormatKitVersionNumber; 13 | 14 | //! Project version string for AnyFormatKit. 15 | FOUNDATION_EXPORT const unsigned char AnyFormatKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /AnyFormatKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'AnyFormatKit' 3 | s.version = '2.5.2' 4 | s.summary = 'Simple text formatting in Swift.' 5 | 6 | s.description = <<-DESC 7 | This framework provide to format text with format like "## ##-###", where # - replaceble symbol. Support format all string or character by character input. 8 | DESC 9 | 10 | s.homepage = 'https://github.com/luximetr/AnyFormatKit' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'luximetr' => 'luximetr.notification@gmail.com' } 13 | s.source = { :git => 'https://github.com/luximetr/AnyFormatKit.git', :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = '9.0' 16 | s.swift_version = '5.0' 17 | 18 | s.source_files = 'Source/**/*' 19 | end 20 | -------------------------------------------------------------------------------- /AnyFormatKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AnyFormatKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Assets/anyformatkit.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luximetr/AnyFormatKit/ae3a965164005b07f81d6aa066520d7ad14ea54e/Assets/anyformatkit.jpeg -------------------------------------------------------------------------------- /Assets/example_card_number.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luximetr/AnyFormatKit/ae3a965164005b07f81d6aa066520d7ad14ea54e/Assets/example_card_number.gif -------------------------------------------------------------------------------- /Assets/example_phone_number.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luximetr/AnyFormatKit/ae3a965164005b07f81d6aa066520d7ad14ea54e/Assets/example_phone_number.gif -------------------------------------------------------------------------------- /Assets/example_placeholder_phone_number.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luximetr/AnyFormatKit/ae3a965164005b07f81d6aa066520d7ad14ea54e/Assets/example_placeholder_phone_number.gif -------------------------------------------------------------------------------- /Assets/example_sum.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luximetr/AnyFormatKit/ae3a965164005b07f81d6aa066520d7ad14ea54e/Assets/example_sum.gif -------------------------------------------------------------------------------- /BundleFiles/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Documentation/AnyFormatKit 0.2.0 MigrationGuide.md: -------------------------------------------------------------------------------- 1 | # AnyFormatKit 0.2.0 Migration Guide 2 | 3 | ## Breaking Changes 4 | 5 | ### SumTextFormatter 6 | 7 | #### Maximum Decimal Characters 8 | 9 | Variable, that allowed to input limited number of characters after decimal separator now get-only. 10 | 11 | ```swift 12 | // open var maximumDecimalCharacters: Int = 2 13 | open var maximumDecimalCharacters: Int { 14 | return numberFormatter.maximumFractionDigits 15 | } 16 | ``` 17 | Now maximumFractionDigits parse from format (number of '#' after decimal separator). 18 | 19 | ```swift 20 | SumTextInputFormatter(textPattern: "#.###,#### $") // 4 '#' after ',' - maximumFractionDigits 21 | ``` 22 | 23 | ## Updates 24 | 25 | #### Format input method 26 | 27 | func formatInput() - method, that format text and return it as result with new caret offset. Now TextInputFormatter use this method in shouldChangeTextIn() by default. 28 | 29 | ```swift 30 | func formatInput(currentText: String, range: NSRange, replacementString text: String) -> FormattedTextValue 31 | ``` 32 | 33 | #### FormattedTextValue 34 | 35 | FormattedTextValue is a tuple, that use for return formatted text and caret offset from begin from input formatter. 36 | 37 | ```swift 38 | public typealias FormattedTextValue = (formattedText: String, caretBeginOffset: Int) 39 | ``` 40 | 41 | #### SumTextFormatter 42 | 43 | Now sum text formatter use NumberFormatter under the hood. 44 | 45 | ```swift 46 | private let numberFormatter: NumberFormatter 47 | ``` 48 | Was added init method with number formatter. Old init method still works. 49 | 50 | ```swift 51 | public init(numberFormatter: NumberFormatter) { 52 | self.numberFormatter = numberFormatter 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /Documentation/AnyFormatKit 1.0.0 MigrationGuide.md: -------------------------------------------------------------------------------- 1 | # AnyFormatKit 1.0.0 Migration Guide 2 | 3 | ## Breaking Changes 4 | 5 | ### TextFormatterProtocol 6 | 7 | - `TextFormatterProtocol` was renamed to `TextFormatter` 8 | - `formattedText(from:)` method renamed to `format()` 9 | - `unformattedText(from:)` method renamed to `unformat()` 10 | 11 | ```swift 12 | public protocol TextFormatter { 13 | func format(_ unformattedText: String?) -> String? 14 | func unformat(_ formattedText: String?) -> String? 15 | } 16 | ``` 17 | 18 | ### TextInputFormatterProtocol 19 | 20 | - `TextInputFormatterProtocol` was renamed to `TextInputFormatter` 21 | - now have only one method `formatInput(currentText:)`, how to use it look at [demo](https://github.com/luximetr/AnyFormatKit/tree/master/Example) project 22 | 23 | ```swift 24 | protocol TextInputFormatter: TextFormatter { 25 | func formatInput(currentText: String, range: NSRange, replacementString text: String) -> FormattedTextValue 26 | } 27 | ``` 28 | 29 | ### TextFormatter 30 | 31 | `TextFormatter` was renamed to `DefaultTextFormatter` 32 | 33 | ### TextInputFormatter 34 | 35 | - `TextInputFormatter` was renamed to `DefaultTextInputFormatter` 36 | - `var allowedSymbolsRegex: String` was removed. Filter moved to separate pod (look at [Filter](https://github.com/Brander-ua/BTextInputFilter)) 37 | - `shouldChangeTextIn(textInput:)` was removed (need to use `formatInput(currentText:)`) 38 | 39 | ### SumTextInputFormatter 40 | 41 | - `var formattedPrefix: String?` was removed 42 | - `var allowedSymbolsRegex: String?` was removed. Filter moved to separate pod (look at [Filter](https://github.com/Brander-ua/BTextInputFilter)) 43 | - `func didBeginEditing()` was removed 44 | - `func shouldChangeTextIn(textInput:)` was removed 45 | 46 | ### Removed classes 47 | 48 | - `MulticastDelegate` 49 | - `TextInput` 50 | - `TextInputDelegate` 51 | - `AttributedTextInputField` 52 | - `AttributedTextInputView` 53 | - `TextInputField` 54 | - `TextInputFieldDelegate` 55 | - `TextInputView` 56 | - `TextInputViewDelegate` 57 | - `TextInputController` 58 | -------------------------------------------------------------------------------- /Documentation/AnyFormatKit 2.4.0 MigrationGuide.md: -------------------------------------------------------------------------------- 1 | # AnyFormatKit 2.4.0 Migration Guide 2 | 3 | ## Breaking Changes 4 | 5 | - `TextFieldPlaceholderInputController` was renamed to `TextFieldStartInputController` 6 | - `TextViewPlaceholderInputController` was renamed to `TextViewStartInputController` 7 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | target 'iOS Example' do 5 | 6 | use_frameworks! 7 | 8 | pod 'SnapKit', '~> 4.0.0' 9 | pod 'AnyFormatKit', :path => '../../' 10 | 11 | end 12 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AnyFormatKit (2.5.1) 3 | - SnapKit (4.0.1) 4 | 5 | DEPENDENCIES: 6 | - AnyFormatKit (from `../../`) 7 | - SnapKit (~> 4.0.0) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SnapKit 12 | 13 | EXTERNAL SOURCES: 14 | AnyFormatKit: 15 | :path: "../../" 16 | 17 | SPEC CHECKSUMS: 18 | AnyFormatKit: 4ef60ad3f48c69962d482bb2de0a6d3214e8527b 19 | SnapKit: 0de968a9fec17499afa29683b05d0c775b6d1c29 20 | 21 | PODFILE CHECKSUM: 64ea4beb092a0aaf133ee0f812f932e72d0f81b1 22 | 23 | COCOAPODS: 1.10.1 24 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Local Podspecs/AnyFormatKit.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AnyFormatKit", 3 | "version": "2.5.1", 4 | "summary": "Simple text formatting in Swift.", 5 | "description": "This framework provide to format text with format like \"## ##-###\", where # - replaceble symbol. Support format all string or character by character input.", 6 | "homepage": "https://github.com/luximetr/AnyFormatKit", 7 | "license": { 8 | "type": "MIT", 9 | "file": "LICENSE" 10 | }, 11 | "authors": { 12 | "luximetr": "luximetr.notification@gmail.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/luximetr/AnyFormatKit.git", 16 | "tag": "2.5.1" 17 | }, 18 | "platforms": { 19 | "ios": "9.0" 20 | }, 21 | "swift_versions": "5.0", 22 | "source_files": "Source/**/*", 23 | "swift_version": "5.0" 24 | } 25 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - AnyFormatKit (2.5.1) 3 | - SnapKit (4.0.1) 4 | 5 | DEPENDENCIES: 6 | - AnyFormatKit (from `../../`) 7 | - SnapKit (~> 4.0.0) 8 | 9 | SPEC REPOS: 10 | trunk: 11 | - SnapKit 12 | 13 | EXTERNAL SOURCES: 14 | AnyFormatKit: 15 | :path: "../../" 16 | 17 | SPEC CHECKSUMS: 18 | AnyFormatKit: 4ef60ad3f48c69962d482bb2de0a6d3214e8527b 19 | SnapKit: 0de968a9fec17499afa29683b05d0c775b6d1c29 20 | 21 | PODFILE CHECKSUM: 64ea4beb092a0aaf133ee0f812f932e72d0f81b1 22 | 23 | COCOAPODS: 1.10.1 24 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 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 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintConfig.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | public typealias ConstraintInterfaceLayoutDirection = UIUserInterfaceLayoutDirection 27 | #else 28 | import AppKit 29 | public typealias ConstraintInterfaceLayoutDirection = NSUserInterfaceLayoutDirection 30 | #endif 31 | 32 | 33 | public struct ConstraintConfig { 34 | 35 | public static var interfaceLayoutDirection: ConstraintInterfaceLayoutDirection = .leftToRight 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintDescription.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintDescription { 32 | 33 | internal let item: LayoutConstraintItem 34 | internal var attributes: ConstraintAttributes 35 | internal var relation: ConstraintRelation? = nil 36 | internal var sourceLocation: (String, UInt)? = nil 37 | internal var label: String? = nil 38 | internal var related: ConstraintItem? = nil 39 | internal var multiplier: ConstraintMultiplierTarget = 1.0 40 | internal var constant: ConstraintConstantTarget = 0.0 41 | internal var priority: ConstraintPriorityTarget = 1000.0 42 | internal lazy var constraint: Constraint? = { 43 | guard let relation = self.relation, 44 | let related = self.related, 45 | let sourceLocation = self.sourceLocation else { 46 | return nil 47 | } 48 | let from = ConstraintItem(target: self.item, attributes: self.attributes) 49 | 50 | return Constraint( 51 | from: from, 52 | to: related, 53 | relation: relation, 54 | sourceLocation: sourceLocation, 55 | label: self.label, 56 | multiplier: self.multiplier, 57 | constant: self.constant, 58 | priority: self.priority 59 | ) 60 | }() 61 | 62 | // MARK: Initialization 63 | 64 | internal init(item: LayoutConstraintItem, attributes: ConstraintAttributes) { 65 | self.item = item 66 | self.attributes = attributes 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintInsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintInsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintInsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintInsetTarget { 38 | } 39 | 40 | extension Float: ConstraintInsetTarget { 41 | } 42 | 43 | extension Double: ConstraintInsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintInsetTarget { 47 | } 48 | 49 | extension ConstraintInsets: ConstraintInsetTarget { 50 | } 51 | 52 | extension ConstraintInsetTarget { 53 | 54 | internal var constraintInsetTargetValue: ConstraintInsets { 55 | if let amount = self as? ConstraintInsets { 56 | return amount 57 | } else if let amount = self as? Float { 58 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 59 | } else if let amount = self as? Double { 60 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 61 | } else if let amount = self as? CGFloat { 62 | return ConstraintInsets(top: amount, left: amount, bottom: amount, right: amount) 63 | } else if let amount = self as? Int { 64 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 65 | } else if let amount = self as? UInt { 66 | return ConstraintInsets(top: CGFloat(amount), left: CGFloat(amount), bottom: CGFloat(amount), right: CGFloat(amount)) 67 | } else { 68 | return ConstraintInsets(top: 0, left: 0, bottom: 0, right: 0) 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintInsets.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintInsets = UIEdgeInsets 33 | #else 34 | public typealias ConstraintInsets = NSEdgeInsets 35 | #endif 36 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public final class ConstraintItem { 32 | 33 | internal weak var target: AnyObject? 34 | internal let attributes: ConstraintAttributes 35 | 36 | internal init(target: AnyObject?, attributes: ConstraintAttributes) { 37 | self.target = target 38 | self.attributes = attributes 39 | } 40 | 41 | internal var layoutConstraintItem: LayoutConstraintItem? { 42 | return self.target as? LayoutConstraintItem 43 | } 44 | 45 | } 46 | 47 | public func ==(lhs: ConstraintItem, rhs: ConstraintItem) -> Bool { 48 | // pointer equality 49 | guard lhs !== rhs else { 50 | return true 51 | } 52 | 53 | // must both have valid targets and identical attributes 54 | guard let target1 = lhs.target, 55 | let target2 = rhs.target, 56 | target1 === target2 && lhs.attributes == rhs.attributes else { 57 | return false 58 | } 59 | 60 | return true 61 | } 62 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintLayoutGuide+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 9.0, OSX 10.11, *) 30 | public extension ConstraintLayoutGuide { 31 | 32 | public var snp: ConstraintLayoutGuideDSL { 33 | return ConstraintLayoutGuideDSL(guide: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintLayoutGuide.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 9.0, *) 33 | public typealias ConstraintLayoutGuide = UILayoutGuide 34 | #else 35 | @available(OSX 10.11, *) 36 | public typealias ConstraintLayoutGuide = NSLayoutGuide 37 | #endif 38 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintLayoutGuideDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 9.0, OSX 10.11, *) 32 | public struct ConstraintLayoutGuideDSL: ConstraintAttributesDSL { 33 | 34 | @discardableResult 35 | public func prepareConstraints(_ closure: (_ make: ConstraintMaker) -> Void) -> [Constraint] { 36 | return ConstraintMaker.prepareConstraints(item: self.guide, closure: closure) 37 | } 38 | 39 | public func makeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 40 | ConstraintMaker.makeConstraints(item: self.guide, closure: closure) 41 | } 42 | 43 | public func remakeConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 44 | ConstraintMaker.remakeConstraints(item: self.guide, closure: closure) 45 | } 46 | 47 | public func updateConstraints(_ closure: (_ make: ConstraintMaker) -> Void) { 48 | ConstraintMaker.updateConstraints(item: self.guide, closure: closure) 49 | } 50 | 51 | public func removeConstraints() { 52 | ConstraintMaker.removeConstraints(item: self.guide) 53 | } 54 | 55 | public var target: AnyObject? { 56 | return self.guide 57 | } 58 | 59 | internal let guide: ConstraintLayoutGuide 60 | 61 | internal init(guide: ConstraintLayoutGuide) { 62 | self.guide = guide 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintLayoutSupport.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | @available(iOS 8.0, *) 33 | public typealias ConstraintLayoutSupport = UILayoutSupport 34 | #else 35 | public class ConstraintLayoutSupport {} 36 | #endif 37 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintLayoutSupportDSL.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | @available(iOS 8.0, *) 32 | public struct ConstraintLayoutSupportDSL: ConstraintDSL { 33 | 34 | public var target: AnyObject? { 35 | return self.support 36 | } 37 | 38 | internal let support: ConstraintLayoutSupport 39 | 40 | internal init(support: ConstraintLayoutSupport) { 41 | self.support = support 42 | 43 | } 44 | 45 | public var top: ConstraintItem { 46 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.top) 47 | } 48 | 49 | public var bottom: ConstraintItem { 50 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.bottom) 51 | } 52 | 53 | public var height: ConstraintItem { 54 | return ConstraintItem(target: self.target, attributes: ConstraintAttributes.height) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintMakerEditable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerEditable: ConstraintMakerPriortizable { 32 | 33 | @discardableResult 34 | public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 35 | self.description.multiplier = amount 36 | return self 37 | } 38 | 39 | @discardableResult 40 | public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable { 41 | return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue) 42 | } 43 | 44 | @discardableResult 45 | public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable { 46 | self.description.constant = amount.constraintOffsetTargetValue 47 | return self 48 | } 49 | 50 | @discardableResult 51 | public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable { 52 | self.description.constant = amount.constraintInsetTargetValue 53 | return self 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintMakerFinalizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerFinalizable { 32 | 33 | internal let description: ConstraintDescription 34 | 35 | internal init(_ description: ConstraintDescription) { 36 | self.description = description 37 | } 38 | 39 | @discardableResult 40 | public func labeled(_ label: String) -> ConstraintMakerFinalizable { 41 | self.description.label = label 42 | return self 43 | } 44 | 45 | public var constraint: Constraint { 46 | return self.description.constraint! 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintMakerPriortizable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class ConstraintMakerPriortizable: ConstraintMakerFinalizable { 32 | 33 | @discardableResult 34 | public func priority(_ amount: ConstraintPriority) -> ConstraintMakerFinalizable { 35 | self.description.priority = amount.value 36 | return self 37 | } 38 | 39 | @discardableResult 40 | public func priority(_ amount: ConstraintPriorityTarget) -> ConstraintMakerFinalizable { 41 | self.description.priority = amount 42 | return self 43 | } 44 | 45 | @available(*, deprecated:3.0, message:"Use priority(.required) instead.") 46 | @discardableResult 47 | public func priorityRequired() -> ConstraintMakerFinalizable { 48 | return self.priority(.required) 49 | } 50 | 51 | @available(*, deprecated:3.0, message:"Use priority(.high) instead.") 52 | @discardableResult 53 | public func priorityHigh() -> ConstraintMakerFinalizable { 54 | return self.priority(.high) 55 | } 56 | 57 | @available(*, deprecated:3.0, message:"Use priority(.medium) instead.") 58 | @discardableResult 59 | public func priorityMedium() -> ConstraintMakerFinalizable { 60 | return self.priority(.medium) 61 | } 62 | 63 | @available(*, deprecated:3.0, message:"Use priority(.low) instead.") 64 | @discardableResult 65 | public func priorityLow() -> ConstraintMakerFinalizable { 66 | return self.priority(.low) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintMultiplierTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintMultiplierTarget { 32 | 33 | var constraintMultiplierTargetValue: CGFloat { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintMultiplierTarget { 38 | 39 | public var constraintMultiplierTargetValue: CGFloat { 40 | return CGFloat(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintMultiplierTarget { 46 | 47 | public var constraintMultiplierTargetValue: CGFloat { 48 | return CGFloat(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintMultiplierTarget { 54 | 55 | public var constraintMultiplierTargetValue: CGFloat { 56 | return CGFloat(self) 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintMultiplierTarget { 62 | 63 | public var constraintMultiplierTargetValue: CGFloat { 64 | return CGFloat(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintMultiplierTarget { 70 | 71 | public var constraintMultiplierTargetValue: CGFloat { 72 | return self 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintOffsetTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintOffsetTarget: ConstraintConstantTarget { 32 | } 33 | 34 | extension Int: ConstraintOffsetTarget { 35 | } 36 | 37 | extension UInt: ConstraintOffsetTarget { 38 | } 39 | 40 | extension Float: ConstraintOffsetTarget { 41 | } 42 | 43 | extension Double: ConstraintOffsetTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintOffsetTarget { 47 | } 48 | 49 | extension ConstraintOffsetTarget { 50 | 51 | internal var constraintOffsetTargetValue: CGFloat { 52 | let offset: CGFloat 53 | if let amount = self as? Float { 54 | offset = CGFloat(amount) 55 | } else if let amount = self as? Double { 56 | offset = CGFloat(amount) 57 | } else if let amount = self as? CGFloat { 58 | offset = CGFloat(amount) 59 | } else if let amount = self as? Int { 60 | offset = CGFloat(amount) 61 | } else if let amount = self as? UInt { 62 | offset = CGFloat(amount) 63 | } else { 64 | offset = 0.0 65 | } 66 | return offset 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintPriority.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | public struct ConstraintPriority : ExpressibleByFloatLiteral, Equatable, Strideable { 31 | public typealias FloatLiteralType = Float 32 | 33 | public let value: Float 34 | 35 | public init(floatLiteral value: Float) { 36 | self.value = value 37 | } 38 | 39 | public init(_ value: Float) { 40 | self.value = value 41 | } 42 | 43 | public static var required: ConstraintPriority { 44 | return 1000.0 45 | } 46 | 47 | public static var high: ConstraintPriority { 48 | return 750.0 49 | } 50 | 51 | public static var medium: ConstraintPriority { 52 | #if os(OSX) 53 | return 501.0 54 | #else 55 | return 500.0 56 | #endif 57 | 58 | } 59 | 60 | public static var low: ConstraintPriority { 61 | return 250.0 62 | } 63 | 64 | public static func ==(lhs: ConstraintPriority, rhs: ConstraintPriority) -> Bool { 65 | return lhs.value == rhs.value 66 | } 67 | 68 | // MARK: Strideable 69 | 70 | public func advanced(by n: FloatLiteralType) -> ConstraintPriority { 71 | return ConstraintPriority(floatLiteral: value + n) 72 | } 73 | 74 | public func distance(to other: ConstraintPriority) -> FloatLiteralType { 75 | return other.value - value 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintPriorityTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintPriorityTarget { 32 | 33 | var constraintPriorityTargetValue: Float { get } 34 | 35 | } 36 | 37 | extension Int: ConstraintPriorityTarget { 38 | 39 | public var constraintPriorityTargetValue: Float { 40 | return Float(self) 41 | } 42 | 43 | } 44 | 45 | extension UInt: ConstraintPriorityTarget { 46 | 47 | public var constraintPriorityTargetValue: Float { 48 | return Float(self) 49 | } 50 | 51 | } 52 | 53 | extension Float: ConstraintPriorityTarget { 54 | 55 | public var constraintPriorityTargetValue: Float { 56 | return self 57 | } 58 | 59 | } 60 | 61 | extension Double: ConstraintPriorityTarget { 62 | 63 | public var constraintPriorityTargetValue: Float { 64 | return Float(self) 65 | } 66 | 67 | } 68 | 69 | extension CGFloat: ConstraintPriorityTarget { 70 | 71 | public var constraintPriorityTargetValue: Float { 72 | return Float(self) 73 | } 74 | 75 | } 76 | 77 | #if os(iOS) || os(tvOS) 78 | extension UILayoutPriority: ConstraintPriorityTarget { 79 | 80 | public var constraintPriorityTargetValue: Float { 81 | return self.rawValue 82 | } 83 | 84 | } 85 | #endif 86 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintRelatableTarget.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol ConstraintRelatableTarget { 32 | } 33 | 34 | extension Int: ConstraintRelatableTarget { 35 | } 36 | 37 | extension UInt: ConstraintRelatableTarget { 38 | } 39 | 40 | extension Float: ConstraintRelatableTarget { 41 | } 42 | 43 | extension Double: ConstraintRelatableTarget { 44 | } 45 | 46 | extension CGFloat: ConstraintRelatableTarget { 47 | } 48 | 49 | extension CGSize: ConstraintRelatableTarget { 50 | } 51 | 52 | extension CGPoint: ConstraintRelatableTarget { 53 | } 54 | 55 | extension ConstraintInsets: ConstraintRelatableTarget { 56 | } 57 | 58 | extension ConstraintItem: ConstraintRelatableTarget { 59 | } 60 | 61 | extension ConstraintView: ConstraintRelatableTarget { 62 | } 63 | 64 | @available(iOS 9.0, OSX 10.11, *) 65 | extension ConstraintLayoutGuide: ConstraintRelatableTarget { 66 | } 67 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintRelation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | internal enum ConstraintRelation : Int { 32 | case equal = 1 33 | case lessThanOrEqual 34 | case greaterThanOrEqual 35 | 36 | internal var layoutRelation: LayoutRelation { 37 | get { 38 | switch(self) { 39 | case .equal: 40 | return .equal 41 | case .lessThanOrEqual: 42 | return .lessThanOrEqual 43 | case .greaterThanOrEqual: 44 | return .greaterThanOrEqual 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/ConstraintView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | #if os(iOS) || os(tvOS) 32 | public typealias ConstraintView = UIView 33 | #else 34 | public typealias ConstraintView = NSView 35 | #endif 36 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/LayoutConstraint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public class LayoutConstraint : NSLayoutConstraint { 32 | 33 | public var label: String? { 34 | get { 35 | return self.identifier 36 | } 37 | set { 38 | self.identifier = newValue 39 | } 40 | } 41 | 42 | internal weak var constraint: Constraint? = nil 43 | 44 | } 45 | 46 | internal func ==(lhs: LayoutConstraint, rhs: LayoutConstraint) -> Bool { 47 | guard lhs.firstItem === rhs.firstItem && 48 | lhs.secondItem === rhs.secondItem && 49 | lhs.firstAttribute == rhs.firstAttribute && 50 | lhs.secondAttribute == rhs.secondAttribute && 51 | lhs.relation == rhs.relation && 52 | lhs.priority == rhs.priority && 53 | lhs.multiplier == rhs.multiplier else { 54 | return false 55 | } 56 | return true 57 | } 58 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/LayoutConstraintItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #else 27 | import AppKit 28 | #endif 29 | 30 | 31 | public protocol LayoutConstraintItem: class { 32 | } 33 | 34 | @available(iOS 9.0, OSX 10.11, *) 35 | extension ConstraintLayoutGuide : LayoutConstraintItem { 36 | } 37 | 38 | extension ConstraintView : LayoutConstraintItem { 39 | } 40 | 41 | 42 | extension LayoutConstraintItem { 43 | 44 | internal func prepare() { 45 | if let view = self as? ConstraintView { 46 | view.translatesAutoresizingMaskIntoConstraints = false 47 | } 48 | } 49 | 50 | internal var superview: ConstraintView? { 51 | if let view = self as? ConstraintView { 52 | return view.superview 53 | } 54 | 55 | if #available(iOS 9.0, OSX 10.11, *), let guide = self as? ConstraintLayoutGuide { 56 | return guide.owningView 57 | } 58 | 59 | return nil 60 | } 61 | internal var constraints: [Constraint] { 62 | return self.constraintsSet.allObjects as! [Constraint] 63 | } 64 | 65 | internal func add(constraints: [Constraint]) { 66 | let constraintsSet = self.constraintsSet 67 | for constraint in constraints { 68 | constraintsSet.add(constraint) 69 | } 70 | } 71 | 72 | internal func remove(constraints: [Constraint]) { 73 | let constraintsSet = self.constraintsSet 74 | for constraint in constraints { 75 | constraintsSet.remove(constraint) 76 | } 77 | } 78 | 79 | private var constraintsSet: NSMutableSet { 80 | let constraintsSet: NSMutableSet 81 | 82 | if let existing = objc_getAssociatedObject(self, &constraintsKey) as? NSMutableSet { 83 | constraintsSet = existing 84 | } else { 85 | constraintsSet = NSMutableSet() 86 | objc_setAssociatedObject(self, &constraintsKey, constraintsSet, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 87 | } 88 | return constraintsSet 89 | 90 | } 91 | 92 | } 93 | private var constraintsKey: UInt8 = 0 94 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/Typealiases.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | import Foundation 25 | 26 | #if os(iOS) || os(tvOS) 27 | import UIKit 28 | #if swift(>=4.2) 29 | typealias LayoutRelation = NSLayoutConstraint.Relation 30 | typealias LayoutAttribute = NSLayoutConstraint.Attribute 31 | #else 32 | typealias LayoutRelation = NSLayoutRelation 33 | typealias LayoutAttribute = NSLayoutAttribute 34 | #endif 35 | typealias LayoutPriority = UILayoutPriority 36 | #else 37 | import AppKit 38 | typealias LayoutRelation = NSLayoutConstraint.Relation 39 | typealias LayoutAttribute = NSLayoutConstraint.Attribute 40 | typealias LayoutPriority = NSLayoutConstraint.Priority 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/SnapKit/Source/UILayoutSupport+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapKit 3 | // 4 | // Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | #if os(iOS) || os(tvOS) 25 | import UIKit 26 | #endif 27 | 28 | 29 | @available(iOS 8.0, *) 30 | public extension ConstraintLayoutSupport { 31 | 32 | public var snp: ConstraintLayoutSupportDSL { 33 | return ConstraintLayoutSupportDSL(support: self) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit-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 | 2.5.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_AnyFormatKit : NSObject 3 | @end 4 | @implementation PodsDummy_AnyFormatKit 5 | @end 6 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit-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/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit-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 AnyFormatKitVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char AnyFormatKitVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AnyFormatKit 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/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module AnyFormatKit { 2 | umbrella header "AnyFormatKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/AnyFormatKit/AnyFormatKit.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/AnyFormatKit 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/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS 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/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS Example-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## AnyFormatKit 5 | 6 | Copyright (c) 2021 luximetr 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 | ## SnapKit 28 | 29 | Copyright (c) 2011-Present SnapKit Team - https://github.com/SnapKit 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | 49 | Generated by CocoaPods - https://cocoapods.org 50 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_iOS_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_iOS_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS 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_iOS_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_iOS_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS 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}/AnyFormatKit" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AnyFormatKit/AnyFormatKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "AnyFormatKit" -framework "SnapKit" 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/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_iOS_Example { 2 | umbrella header "Pods-iOS Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/Pods-iOS Example/Pods-iOS 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}/AnyFormatKit" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/AnyFormatKit/AnyFormatKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers" 6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 7 | OTHER_LDFLAGS = $(inherited) -framework "AnyFormatKit" -framework "SnapKit" 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/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit-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 | 4.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_SnapKit : NSObject 3 | @end 4 | @implementation PodsDummy_SnapKit 5 | @end 6 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit-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/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit-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 SnapKitVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char SnapKitVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit 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}/SnapKit 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/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit.modulemap: -------------------------------------------------------------------------------- 1 | framework module SnapKit { 2 | umbrella header "SnapKit-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/Pods/Target Support Files/SnapKit/SnapKit.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/SnapKit 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}/SnapKit 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/CocoapodsExample/iOS Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 01.11.2017. 6 | // Copyright © 2017 Oleksandr Orlov. 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 invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 24.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import AnyFormatKit 11 | 12 | class ExampleViewController: UIViewController { 13 | 14 | // MARK: - View 15 | 16 | private let selfView = ExampleView() 17 | 18 | // MARK: - Controllers 19 | 20 | let phoneNumberInputController = TextFieldInputController() 21 | let cardNumberInputController = TextFieldStartInputController() 22 | let cardExpirationInputController = TextFieldStartInputController() 23 | let cardCVVInputController = TextFieldStartInputController() 24 | let moneyInputController = TextFieldStartInputController() 25 | 26 | // MARK: - Formatters 27 | 28 | let phoneNumberFormatter = DefaultTextInputFormatter(textPattern: "+5# (###) ###-##-##") 29 | let cardNumberFormatter = PlaceholderTextInputFormatter(textPattern: "#### #### #### ####") 30 | let cardExpirationFormatter = PlaceholderTextInputFormatter(textPattern: "__/__", patternSymbol: "_") 31 | let cardCVVFormatter = PlaceholderTextInputFormatter(textPattern: "***", patternSymbol: "*") 32 | let moneyFormatter = SumTextInputFormatter(textPattern: "# ###,## $") 33 | 34 | // MARK: - View life cycle 35 | 36 | override func loadView() { 37 | view = selfView 38 | } 39 | 40 | override func viewDidLoad() { 41 | super.viewDidLoad() 42 | setup() 43 | } 44 | 45 | // MARK: - Setup 46 | 47 | private func setup() { 48 | setupPhoneNumberController() 49 | setupCardNumberController() 50 | setupCardExpirationController() 51 | setupCardCVVController() 52 | setupMoneyController() 53 | } 54 | 55 | // MARK: - Setup phoneNumber 56 | private func setupPhoneNumberController() { 57 | phoneNumberInputController.formatter = phoneNumberFormatter 58 | selfView.phoneNumberInputView.textField.delegate = phoneNumberInputController 59 | } 60 | 61 | // MARK: - Setup cardNumber 62 | private func setupCardNumberController() { 63 | cardNumberInputController.formatter = cardNumberFormatter 64 | selfView.cardNumberInputView.cardNumberTextField.delegate = cardNumberInputController 65 | selfView.cardNumberInputView.cardNumberTextField.text = cardNumberFormatter.format("") 66 | } 67 | 68 | private func setupCardExpirationController() { 69 | cardExpirationInputController.formatter = cardExpirationFormatter 70 | selfView.cardNumberInputView.expirationTextField.delegate = cardExpirationInputController 71 | selfView.cardNumberInputView.expirationTextField.text = cardExpirationFormatter.format("") 72 | } 73 | 74 | private func setupCardCVVController() { 75 | cardCVVInputController.formatter = cardCVVFormatter 76 | selfView.cardNumberInputView.cvvTextField.delegate = cardCVVInputController 77 | selfView.cardNumberInputView.cvvTextField.text = cardCVVFormatter.format("") 78 | } 79 | 80 | // MARK: - Setup money 81 | 82 | private func setupMoneyController() { 83 | moneyInputController.formatter = moneyFormatter 84 | selfView.moneyInputView.textField.delegate = moneyInputController 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Helpers/CardInfoView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardInfoView.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 24.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CardInfoView: InitView { 12 | 13 | // MARK: - UI elements 14 | 15 | let titleLabel = UILabel() 16 | let cardNumberTextField = UITextField() 17 | let expirationTextField = UITextField() 18 | let cvvTextField = UITextField() 19 | 20 | // MARK: - Setup 21 | 22 | override func setup() { 23 | super.setup() 24 | setupTitleLabel() 25 | setupCardNumberTextField() 26 | setupExpirationTextField() 27 | setupCvvTextField() 28 | } 29 | 30 | // MARK: - Prepare layout 31 | 32 | override func prepareLayout() { 33 | super.prepareLayout() 34 | addSubview(titleLabel) 35 | addSubview(cardNumberTextField) 36 | addSubview(expirationTextField) 37 | addSubview(cvvTextField) 38 | prepareLayoutTitleLabel() 39 | prepareLayoutCardNumberTextField() 40 | prepareLayoutExpirationTextField() 41 | prepareLayoutCvvTextField() 42 | } 43 | 44 | // MARK: - Setup titleLabel 45 | 46 | private func setupTitleLabel() { 47 | titleLabel.textColor = .white 48 | } 49 | 50 | private func prepareLayoutTitleLabel() { 51 | titleLabel.snp.makeConstraints { make in 52 | make.leading.top.trailing.equalToSuperview() 53 | } 54 | } 55 | 56 | // MARK: - Setup cardNumberTextField 57 | 58 | private func setupCardNumberTextField() { 59 | cardNumberTextField.backgroundColor = .darkGray 60 | cardNumberTextField.textColor = .white 61 | cardNumberTextField.font = UIFont.monospaced(ofSize: 18) 62 | } 63 | 64 | private func prepareLayoutCardNumberTextField() { 65 | cardNumberTextField.snp.makeConstraints { make in 66 | make.leading.trailing.equalToSuperview() 67 | make.top.equalTo(titleLabel.snp.bottom).offset(1) 68 | make.height.equalTo(44) 69 | } 70 | } 71 | 72 | // MARK: - Setup expirationTextField 73 | 74 | private func setupExpirationTextField() { 75 | expirationTextField.backgroundColor = .darkGray 76 | expirationTextField.textColor = .white 77 | expirationTextField.font = UIFont.monospaced(ofSize: 18) 78 | } 79 | 80 | private func prepareLayoutExpirationTextField() { 81 | expirationTextField.snp.makeConstraints { make in 82 | make.leading.bottom.equalToSuperview() 83 | make.width.equalTo(120) 84 | make.height.equalTo(44) 85 | make.top.equalTo(cardNumberTextField.snp.bottom).offset(1) 86 | } 87 | } 88 | 89 | // MARK: - Setup cvvTextField 90 | 91 | private func setupCvvTextField() { 92 | cvvTextField.backgroundColor = .darkGray 93 | cvvTextField.textColor = .white 94 | cvvTextField.font = UIFont.monospaced(ofSize: 18) 95 | } 96 | 97 | private func prepareLayoutCvvTextField() { 98 | cvvTextField.snp.makeConstraints { make in 99 | make.bottom.height.equalTo(expirationTextField) 100 | make.leading.equalTo(expirationTextField.snp.trailing).offset(1) 101 | make.width.equalTo(70) 102 | } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Helpers/InitView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InitView.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 24.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import SnapKit 11 | 12 | class InitView: UIView { 13 | 14 | convenience init() { 15 | self.init(frame: .zero) 16 | } 17 | 18 | override init(frame: CGRect) { 19 | super.init(frame: frame) 20 | intialSetup() 21 | } 22 | 23 | required init?(coder: NSCoder) { 24 | super.init(coder: coder) 25 | intialSetup() 26 | } 27 | 28 | private func intialSetup() { 29 | setup() 30 | prepareLayout() 31 | } 32 | 33 | func prepareLayout() { 34 | 35 | } 36 | 37 | func setup() { 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Helpers/TitleTextFieldView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TitleTextFieldView.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 24.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TitleTextFieldView: InitView { 12 | 13 | // MARK: - UI elements 14 | 15 | let titleLabel = UILabel() 16 | let textField = UITextField() 17 | 18 | // MARK: - Setup 19 | 20 | override func setup() { 21 | super.setup() 22 | setupTitleLabel() 23 | setupTextField() 24 | } 25 | 26 | // MARK: - Prepare layout 27 | 28 | override func prepareLayout() { 29 | super.prepareLayout() 30 | addSubview(titleLabel) 31 | addSubview(textField) 32 | prepareLayoutTitleLabel() 33 | prepareLayoutTextField() 34 | } 35 | 36 | // MARK: - Setup titleLabel 37 | 38 | private func setupTitleLabel() { 39 | titleLabel.textColor = .white 40 | } 41 | 42 | private func prepareLayoutTitleLabel() { 43 | titleLabel.snp.makeConstraints { make in 44 | make.leading.top.trailing.equalToSuperview() 45 | } 46 | } 47 | 48 | // MARK: - Setup textField 49 | 50 | private func setupTextField() { 51 | textField.textColor = .white 52 | textField.backgroundColor = .darkGray 53 | textField.font = .monospaced(ofSize: 18) 54 | } 55 | 56 | private func prepareLayoutTextField() { 57 | textField.snp.makeConstraints { make in 58 | make.leading.trailing.equalTo(titleLabel) 59 | make.top.equalTo(titleLabel.snp.bottom).offset(1) 60 | make.bottom.equalToSuperview() 61 | make.height.equalTo(44) 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Helpers/UIFont+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+Extension.swift 3 | // iOS Example 4 | // 5 | // Created by Oleksandr Orlov on 24.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIFont { 12 | 13 | static func monospaced(ofSize: CGFloat) -> UIFont { 14 | if #available(iOS 13.0, *) { 15 | return UIFont.monospacedSystemFont(ofSize: ofSize, weight: .regular) 16 | } else if #available(iOS 9.0, *) { 17 | return UIFont.monospacedDigitSystemFont(ofSize: ofSize, weight: .regular) 18 | } else { 19 | return UIFont.init(name: "Helvetica Neue", size: ofSize) ?? UIFont() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Example/CocoapodsExample/iOS Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarStyle 32 | UIStatusBarStyleLightContent 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | UIViewControllerBasedStatusBarAppearance 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "AnyFormatKit", 6 | "repositoryURL": "https://github.com/luximetr/AnyFormatKit", 7 | "state": { 8 | "branch": null, 9 | "revision": "27b35c984c1c81e74c8be5273f7b2dc5250cb5cc", 10 | "version": "2.5.1" 11 | } 12 | }, 13 | { 14 | "package": "SnapKit", 15 | "repositoryURL": "https://github.com/SnapKit/SnapKit", 16 | "state": { 17 | "branch": null, 18 | "revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6", 19 | "version": "5.0.1" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | // Override point for customization after application launch. 17 | return true 18 | } 19 | 20 | // MARK: UISceneSession Lifecycle 21 | 22 | @available(iOS 13.0, *) 23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 24 | // Called when a new scene session is being created. 25 | // Use this method to select a configuration to create the new scene with. 26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 27 | } 28 | 29 | @available(iOS 13.0, *) 30 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 31 | // Called when the user discards a scene session. 32 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 33 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 34 | } 35 | 36 | 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/ExampleViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExampleViewController.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | import AnyFormatKit 10 | 11 | class ExampleViewController: UIViewController { 12 | 13 | // MARK: - View 14 | 15 | private let selfView = ExampleView() 16 | 17 | // MARK: - Controllers 18 | 19 | let phoneNumberInputController = TextFieldInputController() 20 | let cardNumberInputController = TextFieldStartInputController() 21 | let cardExpirationInputController = TextFieldStartInputController() 22 | let cardCVVInputController = TextFieldStartInputController() 23 | let moneyInputController = TextFieldStartInputController() 24 | 25 | // MARK: - Formatters 26 | 27 | let phoneNumberFormatter = DefaultTextInputFormatter(textPattern: "+5# (###) ###-##-##") 28 | let cardNumberFormatter = PlaceholderTextInputFormatter(textPattern: "#### #### #### ####") 29 | let cardExpirationFormatter = PlaceholderTextInputFormatter(textPattern: "__/__", patternSymbol: "_") 30 | let cardCVVFormatter = PlaceholderTextInputFormatter(textPattern: "***", patternSymbol: "*") 31 | let moneyFormatter = SumTextInputFormatter(textPattern: "# ###,## $") 32 | 33 | // MARK: - View life cycle 34 | 35 | override func loadView() { 36 | view = selfView 37 | } 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | setup() 42 | } 43 | 44 | // MARK: - Setup 45 | 46 | private func setup() { 47 | setupPhoneNumberController() 48 | setupCardNumberController() 49 | setupCardExpirationController() 50 | setupCardCVVController() 51 | setupMoneyController() 52 | } 53 | 54 | // MARK: - Setup phoneNumber 55 | private func setupPhoneNumberController() { 56 | phoneNumberInputController.formatter = phoneNumberFormatter 57 | selfView.phoneNumberInputView.textField.delegate = phoneNumberInputController 58 | } 59 | 60 | // MARK: - Setup cardNumber 61 | private func setupCardNumberController() { 62 | cardNumberInputController.formatter = cardNumberFormatter 63 | selfView.cardNumberInputView.cardNumberTextField.delegate = cardNumberInputController 64 | selfView.cardNumberInputView.cardNumberTextField.text = cardNumberFormatter.format("") 65 | } 66 | 67 | private func setupCardExpirationController() { 68 | cardExpirationInputController.formatter = cardExpirationFormatter 69 | selfView.cardNumberInputView.expirationTextField.delegate = cardExpirationInputController 70 | selfView.cardNumberInputView.expirationTextField.text = cardExpirationFormatter.format("") 71 | } 72 | 73 | private func setupCardCVVController() { 74 | cardCVVInputController.formatter = cardCVVFormatter 75 | selfView.cardNumberInputView.cvvTextField.delegate = cardCVVInputController 76 | selfView.cardNumberInputView.cvvTextField.text = cardCVVFormatter.format("") 77 | } 78 | 79 | // MARK: - Setup money 80 | 81 | private func setupMoneyController() { 82 | moneyInputController.formatter = moneyFormatter 83 | selfView.moneyInputView.textField.delegate = moneyInputController 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Helpers/CardInfoView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CardInfoView.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class CardInfoView: InitView { 11 | 12 | // MARK: - UI elements 13 | 14 | let titleLabel = UILabel() 15 | let cardNumberTextField = UITextField() 16 | let expirationTextField = UITextField() 17 | let cvvTextField = UITextField() 18 | 19 | // MARK: - Setup 20 | 21 | override func setup() { 22 | super.setup() 23 | setupTitleLabel() 24 | setupCardNumberTextField() 25 | setupExpirationTextField() 26 | setupCvvTextField() 27 | } 28 | 29 | // MARK: - Prepare layout 30 | 31 | override func prepareLayout() { 32 | super.prepareLayout() 33 | addSubview(titleLabel) 34 | addSubview(cardNumberTextField) 35 | addSubview(expirationTextField) 36 | addSubview(cvvTextField) 37 | prepareLayoutTitleLabel() 38 | prepareLayoutCardNumberTextField() 39 | prepareLayoutExpirationTextField() 40 | prepareLayoutCvvTextField() 41 | } 42 | 43 | // MARK: - Setup titleLabel 44 | 45 | private func setupTitleLabel() { 46 | titleLabel.textColor = .white 47 | } 48 | 49 | private func prepareLayoutTitleLabel() { 50 | titleLabel.snp.makeConstraints { make in 51 | make.leading.top.trailing.equalToSuperview() 52 | } 53 | } 54 | 55 | // MARK: - Setup cardNumberTextField 56 | 57 | private func setupCardNumberTextField() { 58 | cardNumberTextField.backgroundColor = .darkGray 59 | cardNumberTextField.textColor = .white 60 | cardNumberTextField.font = UIFont.monospaced(ofSize: 18) 61 | } 62 | 63 | private func prepareLayoutCardNumberTextField() { 64 | cardNumberTextField.snp.makeConstraints { make in 65 | make.leading.trailing.equalToSuperview() 66 | make.top.equalTo(titleLabel.snp.bottom).offset(1) 67 | make.height.equalTo(44) 68 | } 69 | } 70 | 71 | // MARK: - Setup expirationTextField 72 | 73 | private func setupExpirationTextField() { 74 | expirationTextField.backgroundColor = .darkGray 75 | expirationTextField.textColor = .white 76 | expirationTextField.font = UIFont.monospaced(ofSize: 18) 77 | } 78 | 79 | private func prepareLayoutExpirationTextField() { 80 | expirationTextField.snp.makeConstraints { make in 81 | make.leading.bottom.equalToSuperview() 82 | make.width.equalTo(120) 83 | make.height.equalTo(44) 84 | make.top.equalTo(cardNumberTextField.snp.bottom).offset(1) 85 | } 86 | } 87 | 88 | // MARK: - Setup cvvTextField 89 | 90 | private func setupCvvTextField() { 91 | cvvTextField.backgroundColor = .darkGray 92 | cvvTextField.textColor = .white 93 | cvvTextField.font = UIFont.monospaced(ofSize: 18) 94 | } 95 | 96 | private func prepareLayoutCvvTextField() { 97 | cvvTextField.snp.makeConstraints { make in 98 | make.bottom.height.equalTo(expirationTextField) 99 | make.leading.equalTo(expirationTextField.snp.trailing).offset(1) 100 | make.width.equalTo(70) 101 | } 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Helpers/InitView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InitView.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | import SnapKit 10 | 11 | class InitView: UIView { 12 | 13 | convenience init() { 14 | self.init(frame: .zero) 15 | } 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | intialSetup() 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | super.init(coder: coder) 24 | intialSetup() 25 | } 26 | 27 | private func intialSetup() { 28 | setup() 29 | prepareLayout() 30 | } 31 | 32 | func prepareLayout() { 33 | 34 | } 35 | 36 | func setup() { 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Helpers/TitleTextFieldView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TitleTextFieldView.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class TitleTextFieldView: InitView { 11 | 12 | // MARK: - UI elements 13 | 14 | let titleLabel = UILabel() 15 | let textField = UITextField() 16 | 17 | // MARK: - Setup 18 | 19 | override func setup() { 20 | super.setup() 21 | setupTitleLabel() 22 | setupTextField() 23 | } 24 | 25 | // MARK: - Prepare layout 26 | 27 | override func prepareLayout() { 28 | super.prepareLayout() 29 | addSubview(titleLabel) 30 | addSubview(textField) 31 | prepareLayoutTitleLabel() 32 | prepareLayoutTextField() 33 | } 34 | 35 | // MARK: - Setup titleLabel 36 | 37 | private func setupTitleLabel() { 38 | titleLabel.textColor = .white 39 | } 40 | 41 | private func prepareLayoutTitleLabel() { 42 | titleLabel.snp.makeConstraints { make in 43 | make.leading.top.trailing.equalToSuperview() 44 | } 45 | } 46 | 47 | // MARK: - Setup textField 48 | 49 | private func setupTextField() { 50 | textField.textColor = .white 51 | textField.backgroundColor = .darkGray 52 | textField.font = .monospaced(ofSize: 18) 53 | } 54 | 55 | private func prepareLayoutTextField() { 56 | textField.snp.makeConstraints { make in 57 | make.leading.trailing.equalTo(titleLabel) 58 | make.top.equalTo(titleLabel.snp.bottom).offset(1) 59 | make.bottom.equalToSuperview() 60 | make.height.equalTo(44) 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Helpers/UIFont+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIFont+Extension.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIFont { 11 | 12 | static func monospaced(ofSize: CGFloat) -> UIFont { 13 | if #available(iOS 13.0, *) { 14 | return UIFont.monospacedSystemFont(ofSize: ofSize, weight: .regular) 15 | } else { 16 | return UIFont.monospacedDigitSystemFont(ofSize: ofSize, weight: .regular) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIApplicationSceneManifest 6 | 7 | UIApplicationSupportsMultipleScenes 8 | 9 | UISceneConfigurations 10 | 11 | UIWindowSceneSessionRoleApplication 12 | 13 | 14 | UISceneConfigurationName 15 | Default Configuration 16 | UISceneDelegateClassName 17 | $(PRODUCT_MODULE_NAME).SceneDelegate 18 | UISceneStoryboardFile 19 | Main 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/SPMExample/AnyFormatKitSPMExample/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // AnyFormatKitSPMExample 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | 12 | var window: UIWindow? 13 | 14 | 15 | @available(iOS 13.0, *) 16 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 17 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 18 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 19 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 20 | guard let _ = (scene as? UIWindowScene) else { return } 21 | } 22 | 23 | @available(iOS 13.0, *) 24 | func sceneDidDisconnect(_ scene: UIScene) { 25 | // Called as the scene is being released by the system. 26 | // This occurs shortly after the scene enters the background, or when its session is discarded. 27 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 28 | // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). 29 | } 30 | 31 | @available(iOS 13.0, *) 32 | func sceneDidBecomeActive(_ scene: UIScene) { 33 | // Called when the scene has moved from an inactive state to an active state. 34 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 35 | } 36 | 37 | @available(iOS 13.0, *) 38 | func sceneWillResignActive(_ scene: UIScene) { 39 | // Called when the scene will move from an active state to an inactive state. 40 | // This may occur due to temporary interruptions (ex. an incoming phone call). 41 | } 42 | 43 | @available(iOS 13.0, *) 44 | func sceneWillEnterForeground(_ scene: UIScene) { 45 | // Called as the scene transitions from the background to the foreground. 46 | // Use this method to undo the changes made on entering the background. 47 | } 48 | 49 | @available(iOS 13.0, *) 50 | func sceneDidEnterBackground(_ scene: UIScene) { 51 | // Called as the scene transitions from the foreground to the background. 52 | // Use this method to save data, release shared resources, and store enough scene-specific state information 53 | // to restore the scene back to its current state. 54 | } 55 | 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 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 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 luximetr 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 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "AnyFormatKit", 7 | platforms: [.iOS(.v9)], 8 | products: [ 9 | .library( 10 | name: "AnyFormatKit", 11 | targets: ["AnyFormatKit"] 12 | ) 13 | ], 14 | targets: [ 15 | .target( 16 | name: "AnyFormatKit", 17 | path: "Source" 18 | ), 19 | .testTarget( 20 | name: "AnyFormatKitTests", 21 | dependencies: ["AnyFormatKit"], 22 | path: "Tests" 23 | ) 24 | ] 25 | ) 26 | -------------------------------------------------------------------------------- /Source/Controllers/TextFieldControllers/TextFieldInputController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldInputController.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class TextFieldInputController: NSObject, UITextFieldDelegate { 12 | 13 | open var formatter: TextInputFormatter? 14 | 15 | open func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 16 | guard let formatter = formatter else { return true } 17 | let result = formatter.formatInput( 18 | currentText: textField.text ?? "", 19 | range: range, 20 | replacementString: string 21 | ) 22 | textField.text = result.formattedText 23 | textField.setCursorLocation(result.caretBeginOffset) 24 | notifyEditingChanged(at: textField) 25 | return false 26 | } 27 | 28 | private func notifyEditingChanged(at textField: UITextField) { 29 | textField.sendActions(for: .editingChanged) 30 | NotificationCenter.default.post( 31 | name: UITextField.textDidChangeNotification, 32 | object: textField 33 | ) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Source/Controllers/TextFieldControllers/TextFieldStartInputController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFieldStartInputController.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 27.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class TextFieldStartInputController: NSObject, UITextFieldDelegate { 12 | 13 | open var formatter: (TextInputFormatter & CaretPositioner)? 14 | 15 | open func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 16 | guard let formatter = formatter else { return true } 17 | let result = formatter.formatInput( 18 | currentText: textField.text ?? "", 19 | range: range, 20 | replacementString: string 21 | ) 22 | textField.text = result.formattedText 23 | textField.setCursorLocation(result.caretBeginOffset) 24 | notifyEditingChanged(at: textField) 25 | return false 26 | } 27 | 28 | open func textFieldDidBeginEditing(_ textField: UITextField) { 29 | guard let formatter = formatter else { return } 30 | let offset = formatter.getCaretOffset(for: textField.text ?? "") 31 | textField.setCursorLocation(offset) 32 | } 33 | 34 | private func notifyEditingChanged(at textField: UITextField) { 35 | textField.sendActions(for: .editingChanged) 36 | NotificationCenter.default.post( 37 | name: UITextField.textDidChangeNotification, 38 | object: textField 39 | ) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Source/Controllers/TextViewControllers/TextViewInputController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextViewInputController.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class TextViewInputController: NSObject, UITextViewDelegate { 12 | 13 | open var formatter: TextInputFormatter? 14 | 15 | open func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { 16 | guard let formatter = formatter else { return true } 17 | let result = formatter.formatInput( 18 | currentText: textView.text, 19 | range: range, 20 | replacementString: text 21 | ) 22 | textView.text = result.formattedText 23 | textView.setCursorLocation(result.caretBeginOffset) 24 | return false 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Source/Controllers/TextViewControllers/TextViewStartInputController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextViewStartInputController.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 27.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class TextViewStartInputController: NSObject, UITextViewDelegate { 12 | 13 | open var formatter: (TextInputFormatter & CaretPositioner)? 14 | 15 | open func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool { 16 | guard let formatter = formatter else { return true } 17 | let result = formatter.formatInput( 18 | currentText: textView.text, 19 | range: range, 20 | replacementString: text 21 | ) 22 | textView.text = result.formattedText 23 | textView.setCursorLocation(result.caretBeginOffset) 24 | return false 25 | } 26 | 27 | open func textViewDidBeginEditing(_ textView: UITextView) { 28 | guard let formatter = formatter else { return } 29 | let offset = formatter.getCaretOffset(for: textView.text) 30 | textView.setCursorLocation(offset) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/Extensions/UITextField+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITextField+Extension.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UITextField { 12 | 13 | func setCursorLocation(_ location: Int) { 14 | guard let cursorLocation = position(from: beginningOfDocument, offset: location) else { return } 15 | DispatchQueue.main.async { [weak self] in 16 | guard let strongSelf = self else { return } 17 | strongSelf.selectedTextRange = strongSelf.textRange(from: cursorLocation, to: cursorLocation) 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Source/Extensions/UITextView+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UITextView+Extension.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UITextView { 12 | 13 | func setCursorLocation(_ location: Int) { 14 | guard let cursorLocation = position(from: beginningOfDocument, offset: location) else { return } 15 | DispatchQueue.main.async { [weak self] in 16 | guard let strongSelf = self else { return } 17 | strongSelf.selectedTextRange = strongSelf.textRange(from: cursorLocation, to: cursorLocation) 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /Source/TextFormatter/DefaultFormatters/Formatters/DefaultTextFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextFormatter.swift 3 | // 4 | // Created by Oleksandr Orlov on 11/14/18. 5 | // Copyright © 2018 Oleksandr Orlov. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | open class DefaultTextFormatter: TextFormatter, TextUnformatter { 11 | 12 | // MARK: - Fields 13 | 14 | /// String, that will use for formatting of string replacing patter symbol, example: patternSymbol - "#", format - "### (###) ###-##-##" 15 | public let textPattern: String 16 | 17 | /// Symbol that will be replace by input symbols 18 | public let patternSymbol: Character 19 | 20 | // MARK: - Life cycle 21 | /** 22 | Initializes formatter with pattern 23 | 24 | - Parameters: 25 | - textPatterm: String, that will use for formatting of string replacing patter symbol 26 | - patternSymbol: Character, that will be replaced by input characters in textPattern 27 | */ 28 | public init(textPattern: String, 29 | patternSymbol: Character = Constants.defaultPatternSymbol) { 30 | self.textPattern = textPattern 31 | self.patternSymbol = patternSymbol 32 | } 33 | 34 | // MARK: - TextFormatter 35 | /** 36 | Formatting text with current textPattern 37 | 38 | - Parameters: 39 | - unformatted: String, that need to be convert with current textPattern 40 | 41 | - Returns: Formatted text with current textPattern 42 | */ 43 | open func format(_ unformattedText: String?) -> String? { 44 | guard let unformattedText = unformattedText else { return nil } 45 | var formatted = "" 46 | var unformattedIndex = 0 47 | var patternIndex = 0 48 | 49 | while patternIndex < textPattern.count && unformattedIndex < unformattedText.count { 50 | guard let patternCharacter = textPattern.characterAt(patternIndex) else { break } 51 | if patternCharacter == patternSymbol { 52 | if let unformattedCharacter = unformattedText.characterAt(unformattedIndex) { 53 | formatted.append(unformattedCharacter) 54 | } 55 | unformattedIndex += 1 56 | } else { 57 | formatted.append(patternCharacter) 58 | } 59 | patternIndex += 1 60 | } 61 | return formatted 62 | } 63 | 64 | /** 65 | Method for convert string, that sutisfy current textPattern, into unformatted string 66 | 67 | - Parameters: 68 | - formatted: String, that will convert 69 | 70 | - Returns: string converted into unformatted with current textPattern 71 | */ 72 | open func unformat(_ formatted: String?) -> String? { 73 | guard let formatted = formatted else { return nil } 74 | var unformatted = String() 75 | var formattedIndex = 0 76 | 77 | while formattedIndex < formatted.count { 78 | if let formattedCharacter = formatted.characterAt(formattedIndex) { 79 | if formattedIndex >= textPattern.count { 80 | unformatted.append(formattedCharacter) 81 | } else if formattedCharacter != textPattern.characterAt(formattedIndex) || formattedCharacter == patternSymbol { 82 | unformatted.append(formattedCharacter) 83 | } 84 | formattedIndex += 1 85 | } 86 | } 87 | return unformatted 88 | } 89 | 90 | public struct Constants { 91 | public static let defaultPatternSymbol: Character = "#" 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Source/TextFormatter/DefaultFormatters/Helpers/DefaultCaretPositionCorrector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultCaretPositionCorrector.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 02.04.2018. 6 | // Copyright © 2018 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class DefaultCaretPositionCorrector { 12 | 13 | let textPattern: String 14 | let patternSymbol: Character 15 | 16 | // MARK: - Life Cycle 17 | init(textPattern: String, patternSymbol: Character) { 18 | self.textPattern = textPattern 19 | self.patternSymbol = patternSymbol 20 | } 21 | 22 | func calculateCaretPositionOffset(newText: String, originalRange range: Range, replacementText: String) -> Int { 23 | var offset = 0 24 | if replacementText.isEmpty { 25 | offset = offsetForRemove(newText: newText, lowerBound: range.lowerBound) 26 | } else { 27 | offset = offsetForInsert(newText: newText, lowerBound: range.lowerBound, replacementLength: replacementText.count) 28 | } 29 | return offset 30 | } 31 | 32 | private func offsetForRemove(newText: String, lowerBound: String.Index) -> Int { 33 | let textPatternLowerBound = textPattern.getSameIndex(asIn: newText, sourceIndex: lowerBound) 34 | let textPatternIndex = textPattern.findIndexBefore(of: patternSymbol, startFrom: textPatternLowerBound) 35 | let index = newText.getSameIndex(asIn: textPattern, sourceIndex: textPatternIndex) 36 | let leftSlice = newText.leftSlice(end: index) 37 | return leftSlice.utf16.count 38 | } 39 | 40 | private func offsetForInsert(newText: String, lowerBound: String.Index, replacementLength: Int) -> Int { 41 | let textPatternLowerBound = textPattern.getSameIndex(asIn: newText, sourceIndex: lowerBound) 42 | let textPatternIndex = textPattern.findIndex(of: patternSymbol, skipFirst: replacementLength, startFrom: textPatternLowerBound) 43 | let index = newText.getSameIndex(asIn: textPattern, sourceIndex: textPatternIndex) 44 | let leftSlice = newText.leftSlice(end: index) 45 | return leftSlice.utf16.count 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/TextFormatter/DefaultFormatters/Helpers/DefaultRangeCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultRangeCalculator.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 27.01.2022. 6 | // 7 | 8 | import Foundation 9 | 10 | class DefaultRangeCalculator { 11 | 12 | func unformattedRange( 13 | currentText: String, 14 | textPattern: String, 15 | from range: Range, 16 | patternSymbol: Character 17 | ) -> Range { 18 | let numberOfFormatCharsBeforeRange = getNumberOfFormatChars( 19 | textPattern: textPattern, 20 | text: currentText, 21 | before: range.lowerBound, 22 | patternSymbol: patternSymbol 23 | ) 24 | let numberOfFormatCharsInRange = getNumberOfFormatChars( 25 | textPattern: textPattern, 26 | text: currentText, 27 | in: range, 28 | patternSymbol: patternSymbol 29 | ) 30 | 31 | return currentText.getRangeWithOffsets( 32 | sourceRange: range, 33 | lowerBoundOffset: -numberOfFormatCharsBeforeRange, 34 | upperBoundOffset: -numberOfFormatCharsInRange 35 | ) 36 | } 37 | 38 | private func getNumberOfFormatChars( 39 | textPattern: String, 40 | text: String, 41 | before beforeIndex: String.Index, 42 | patternSymbol: Character 43 | ) -> Int { 44 | let textLeftSlice = text.leftSlice(end: beforeIndex) 45 | let patternLeftSlice = textPattern.leftSlice(limit: textLeftSlice.count) 46 | var result = 0 47 | for (textSliceChar, patternSliceChar) in zip(textLeftSlice, patternLeftSlice) { 48 | if textSliceChar == patternSliceChar && textSliceChar != patternSymbol { result += 1 } 49 | } 50 | return result 51 | } 52 | 53 | private func getNumberOfFormatChars( 54 | textPattern: String, 55 | text: String, 56 | in range: Range, 57 | patternSymbol: Character 58 | ) -> Int { 59 | let textSlice = text.slice(in: range) 60 | let textPatternRange = textPattern.getSameRange(asIn: text, sourceRange: range) 61 | let patternSlice = textPattern.slice(in: textPatternRange) 62 | 63 | var result = 0 64 | for (textSliceCharIndex, textSliceChar) in textSlice.enumerated() { 65 | let isSameCharacter = patternSlice.isSameCharacter(at: textSliceCharIndex, character: textSliceChar) 66 | if isSameCharacter && textSliceChar != patternSymbol { 67 | result += 1 68 | } 69 | } 70 | return result 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Source/TextFormatter/PlaceholderFormatters/Formatters/PlaceholderTextFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderTextFormatter.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class PlaceholderTextFormatter: TextFormatter, TextUnformatter { 12 | 13 | // MARK: - Properties 14 | 15 | /// String, that will use for formatting of string replacing patter symbol, example: patternSymbol - "#", format - "### (###) ###-##-##" 16 | public let textPattern: String 17 | 18 | /// Symbol that will be replace by input symbols 19 | public let patternSymbol: Character 20 | 21 | // MARK: - Life cycle 22 | 23 | /** 24 | Initializes formatter with pattern 25 | 26 | - Parameters: 27 | - textPatterm: String, that will use for formatting of string replacing patter symbol 28 | - patternSymbol: Character, that will be replaced by input characters in textPattern 29 | */ 30 | public init( 31 | textPattern: String, 32 | patternSymbol: Character = "#" 33 | ) { 34 | self.textPattern = textPattern 35 | self.patternSymbol = patternSymbol 36 | } 37 | 38 | // MARK: - TextFormatter 39 | 40 | open func format(_ unformattedText: String?) -> String? { 41 | guard let unformattedText = unformattedText, !unformattedText.isEmpty else { return textPattern } 42 | var formatted = "" 43 | var unformattedIndex = 0 44 | var patternIndex = 0 45 | 46 | while patternIndex < textPattern.count && unformattedIndex < unformattedText.count { 47 | guard let patternCharacter = textPattern.characterAt(patternIndex) else { break } 48 | if patternCharacter == patternSymbol { 49 | if let unformattedCharacter = unformattedText.characterAt(unformattedIndex) { 50 | formatted.append(unformattedCharacter) 51 | } 52 | unformattedIndex += 1 53 | } else { 54 | formatted.append(patternCharacter) 55 | } 56 | patternIndex += 1 57 | } 58 | if formatted.count < textPattern.count { 59 | let start = textPattern.index(textPattern.startIndex, offsetBy: formatted.count) 60 | let end = textPattern.endIndex 61 | formatted = formatted + textPattern[start.. String? { 69 | guard let formatted = formattedText else { return nil } 70 | var unformatted = String() 71 | var formattedIndex = 0 72 | 73 | while formattedIndex < formatted.count { 74 | if let formattedCharacter = formatted.characterAt(formattedIndex) { 75 | if formattedIndex >= textPattern.count { 76 | unformatted.append(formattedCharacter) 77 | } else if formattedCharacter != textPattern.characterAt(formattedIndex) { 78 | unformatted.append(formattedCharacter) 79 | } 80 | formattedIndex += 1 81 | } 82 | } 83 | return unformatted 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Source/TextFormatter/PlaceholderFormatters/Formatters/PlaceholderTextInputFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderTextInputFormatter.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | open class PlaceholderTextInputFormatter: TextInputFormatter, TextFormatter, TextUnformatter, CaretPositioner { 12 | 13 | // MARK: - Dependencies 14 | 15 | private let caretPositionCorrector: PlaceholderCaretPositionCalculator 16 | private let textFormatter: PlaceholderTextFormatter 17 | private let rangeCalculator: PlaceholderRangeCalculator 18 | 19 | // MARK: - Properties 20 | 21 | var textPattern: String { textFormatter.textPattern } 22 | var patternSymbol: Character { textFormatter.patternSymbol } 23 | 24 | // MARK: - Life cycle 25 | 26 | public init( 27 | textPattern: String, 28 | patternSymbol: Character = "#" 29 | ) { 30 | self.caretPositionCorrector = PlaceholderCaretPositionCalculator( 31 | textPattern: textPattern, 32 | patternSymbol: patternSymbol 33 | ) 34 | self.textFormatter = PlaceholderTextFormatter( 35 | textPattern: textPattern, 36 | patternSymbol: patternSymbol 37 | ) 38 | self.rangeCalculator = PlaceholderRangeCalculator() 39 | } 40 | 41 | // MARK: - TextInputFormatter 42 | 43 | open func formatInput(currentText: String, range: NSRange, replacementString text: String) -> FormattedTextValue { 44 | guard let swiftRange = Range(range, in: currentText) else { return .zero } 45 | let oldUnformattedText = textFormatter.unformat(currentText) ?? "" 46 | 47 | let unformattedCurrentTextRange = rangeCalculator.unformattedRange(currentText: currentText, textPattern: textPattern, from: swiftRange) 48 | let unformattedRange = oldUnformattedText.getSameRange(asIn: currentText, sourceRange: unformattedCurrentTextRange) 49 | 50 | let newText = oldUnformattedText.replacingCharacters(in: unformattedRange, with: text) 51 | 52 | let formattedText = textFormatter.format(newText) ?? "" 53 | let formattedTextRange = formattedText.getSameRange(asIn: currentText, sourceRange: swiftRange) 54 | 55 | let caretOffset = getCorrectedCaretPosition(newText: formattedText, range: formattedTextRange, replacementString: text) 56 | 57 | return FormattedTextValue(formattedText: formattedText, caretBeginOffset: caretOffset) 58 | } 59 | 60 | open func getCaretOffset(for text: String) -> Int { 61 | return caretPositionCorrector.calculateCaretPositionOffset(currentText: text) 62 | } 63 | 64 | // MARK: - TextFormatter 65 | 66 | open func format(_ unformattedText: String?) -> String? { 67 | return textFormatter.format(unformattedText) 68 | } 69 | 70 | // MARK: - TextUnformatter 71 | 72 | open func unformat(_ formattedText: String?) -> String? { 73 | return textFormatter.unformat(formattedText) 74 | } 75 | 76 | // MARK: - Caret position calculation 77 | 78 | private func getCorrectedCaretPosition(newText: String, range: Range, replacementString: String) -> Int { 79 | return caretPositionCorrector.calculateCaretPositionOffset( 80 | newText: newText, 81 | originalRange: range, 82 | replacementText: replacementString 83 | ) 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /Source/TextFormatter/PlaceholderFormatters/Helpers/PlaceholderCaretPositionCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderCaretPositionCalculator.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 25.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class PlaceholderCaretPositionCalculator { 12 | 13 | // MARK: - Properties 14 | let textPattern: String 15 | let patternSymbol: Character 16 | private let defaultFormatter: DefaultTextFormatter 17 | 18 | // MARK: - Life Cycle 19 | init(textPattern: String, patternSymbol: Character) { 20 | self.textPattern = textPattern 21 | self.patternSymbol = patternSymbol 22 | self.defaultFormatter = DefaultTextFormatter(textPattern: textPattern, patternSymbol: patternSymbol) 23 | } 24 | 25 | func calculateCaretPositionOffset(currentText: String) -> Int { 26 | let diff = currentText.getRemovingMatches(toMatch: textPattern) 27 | return diff.utf16Length 28 | } 29 | 30 | func calculateCaretPositionOffset(newText: String, originalRange range: Range, replacementText: String) -> Int { 31 | var offset = 0 32 | if replacementText.isEmpty { 33 | offset = offsetForRemove(newText: newText, lowerBound: range.lowerBound) 34 | } else { 35 | offset = offsetForInsert(newText: newText, lowerBound: range.lowerBound, replacementLength: replacementText.count) 36 | } 37 | return offset 38 | } 39 | 40 | private func offsetForRemove(newText: String, lowerBound: String.Index) -> Int { 41 | let textPatternLowerBound = textPattern.getSameIndex(asIn: newText, sourceIndex: lowerBound) 42 | let textPatternIndex = textPattern.findIndexBefore(of: patternSymbol, startFrom: textPatternLowerBound) 43 | let index = newText.getSameIndex(asIn: textPattern, sourceIndex: textPatternIndex) 44 | let leftSlice = newText.leftSlice(end: index) 45 | return leftSlice.utf16Length 46 | } 47 | 48 | private func offsetForInsert(newText: String, lowerBound: String.Index, replacementLength: Int) -> Int { 49 | let textPatternLowerBound = textPattern.getSameIndex(asIn: newText, sourceIndex: lowerBound) 50 | let textPatternIndex = textPattern.findIndex(of: patternSymbol, skipFirst: replacementLength, startFrom: textPatternLowerBound) 51 | let index = newText.getSameIndex(asIn: textPattern, sourceIndex: textPatternIndex) 52 | let leftSlice = newText.leftSlice(end: index) 53 | let textPatternLeftSlice = textPattern.leftSlice(end: textPatternIndex) 54 | let diff = leftSlice.getRemovingMatches(toMatch: textPatternLeftSlice) 55 | return diff.utf16Length 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Source/TextFormatter/PlaceholderFormatters/Helpers/PlaceholderRangeCalculator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderRangeCalculator.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 16.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class PlaceholderRangeCalculator { 12 | 13 | func unformattedRange( 14 | currentText: String, 15 | textPattern: String, 16 | from range: Range 17 | ) -> Range { 18 | let numberOfFormatCharsBeforeRange = getNumberOfFormatChars( 19 | textPattern: textPattern, 20 | text: currentText, 21 | before: range.lowerBound 22 | ) 23 | let numberOfFormatCharsInRange = getNumberOfFormatChars( 24 | textPattern: textPattern, 25 | text: currentText, 26 | in: range 27 | ) 28 | 29 | return currentText.getRangeWithOffsets( 30 | sourceRange: range, 31 | lowerBoundOffset: -numberOfFormatCharsBeforeRange, 32 | upperBoundOffset: -numberOfFormatCharsInRange 33 | ) 34 | } 35 | 36 | private func getNumberOfFormatChars( 37 | textPattern: String, 38 | text: String, 39 | before: String.Index 40 | ) -> Int { 41 | let textLeftSlice = text.leftSlice(end: before) 42 | let patternLeftSlice = textPattern.leftSlice(limit: textLeftSlice.count) 43 | var result = 0 44 | for (textSliceChar, patternSliceChar) in zip(textLeftSlice, patternLeftSlice) { 45 | if textSliceChar == patternSliceChar { result += 1 } 46 | } 47 | return result 48 | } 49 | 50 | private func getNumberOfFormatChars( 51 | textPattern: String, 52 | text: String, 53 | in range: Range 54 | ) -> Int { 55 | let textSlice = text.slice(in: range) 56 | let textPatternRange = textPattern.getSameRange(asIn: text, sourceRange: range) 57 | let patternSlice = textPattern.slice(in: textPatternRange) 58 | 59 | var result = 0 60 | for (textSliceCharIndex, textSliceChar) in textSlice.enumerated() { 61 | let isSameCharacter = patternSlice.isSameCharacter(at: textSliceCharIndex, character: textSliceChar) 62 | if isSameCharacter { 63 | result += 1 64 | } 65 | } 66 | return result 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Source/TextFormatter/SumFormatters/Helpers/SumFormatParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumFormatParser.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 5/27/19. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class SumFormatParser { 12 | 13 | struct Result { 14 | let prefix: String 15 | let suffix: String 16 | let groupingSeparator: String 17 | let decimalSeparator: String 18 | let groupingSize: Int 19 | let maximumFractionDigits: Int 20 | } 21 | 22 | func parse(format: String, patternSymbol: Character) -> Result { 23 | let prefix = parsePrefix(format: format, patternSymbol: patternSymbol) 24 | let suffix = parseSuffix(format: format, patternSymbol: patternSymbol) 25 | let groupingSeparator = parseGroupingSeparator(format: format, prefix: prefix, patternSymbol: patternSymbol) 26 | let decimalSeparator = parseDecimalSeparator(format: format, suffix: suffix, patternSymbol: patternSymbol) 27 | let groupingSize = parseGroupingSize(format: format, prefix: prefix, groupingSeparator: groupingSeparator, decimalSeparator: decimalSeparator, patternSymbol: patternSymbol) 28 | let maximumFractionDigits = parseMaximumFractionDigits(format: format, decimalSeparator: decimalSeparator, suffix: suffix, patternSymbol: patternSymbol) 29 | return Result(prefix: prefix, 30 | suffix: suffix, 31 | groupingSeparator: groupingSeparator, 32 | decimalSeparator: decimalSeparator, 33 | groupingSize: groupingSize, 34 | maximumFractionDigits: maximumFractionDigits) 35 | } 36 | 37 | private func parsePrefix(format: String, patternSymbol: Character) -> String { 38 | guard format.first != patternSymbol else { return "" } 39 | guard let prefixPart = format.split(separator: patternSymbol).first else { return "" } 40 | return String(prefixPart) 41 | } 42 | 43 | private func parseSuffix(format: String, patternSymbol: Character) -> String { 44 | guard format.last != patternSymbol else { return "" } 45 | guard let suffixPart = format.split(separator: patternSymbol).last else { return "" } 46 | return String(suffixPart) 47 | } 48 | 49 | private func parseGroupingSeparator(format: String, prefix: String, patternSymbol: Character) -> String { 50 | let formatWithoutPrefix = format.removePrefix(prefix) 51 | guard let groupingSeparatorPart = formatWithoutPrefix.split(separator: patternSymbol).first else { return "" } 52 | return String(groupingSeparatorPart) 53 | } 54 | 55 | private func parseDecimalSeparator(format: String, suffix: String, patternSymbol: Character) -> String { 56 | let formatWithoutSuffix = format.removeSuffix(suffix) 57 | guard let decimalSeparatorPart = formatWithoutSuffix.split(separator: patternSymbol).last else { return "" } 58 | return String(decimalSeparatorPart) 59 | } 60 | 61 | private func parseGroupingSize(format: String, prefix: String, groupingSeparator: String, decimalSeparator: String, patternSymbol: Character) -> Int { 62 | let formatWithoutPrefix = format.removePrefix(prefix) 63 | let groupPart = formatWithoutPrefix.slice(from: groupingSeparator, to: decimalSeparator) 64 | return groupPart.count 65 | } 66 | 67 | private func parseMaximumFractionDigits(format: String, decimalSeparator: String, suffix: String, patternSymbol: Character) -> Int { 68 | let fractionDigitsPart = format.slice(from: decimalSeparator, to: suffix) 69 | return fractionDigitsPart.count 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/CaretPositioner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CaretPositioner.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 27.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol CaretPositioner { 12 | func getCaretOffset(for text: String) -> Int 13 | } 14 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/FormattedTextValue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormattedTextValue.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct FormattedTextValue: Equatable { 12 | public let formattedText: String 13 | public let caretBeginOffset: Int 14 | 15 | public init(formattedText: String, caretBeginOffset: Int) { 16 | self.formattedText = formattedText 17 | self.caretBeginOffset = caretBeginOffset 18 | } 19 | 20 | public static var zero: FormattedTextValue { 21 | return FormattedTextValue(formattedText: "", caretBeginOffset: 0) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/TextFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextFormatter.swift 3 | // TextInput 4 | // 5 | // Created by Oleksandr Orlov on 18.10.2017. 6 | // Copyright © 2017 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Interface of text formatter 12 | public protocol TextFormatter { 13 | /** 14 | Formatting text with current textPattern 15 | 16 | - Parameters: 17 | - unformatted: String to convert 18 | 19 | - Returns: Formatted text 20 | */ 21 | func format(_ unformattedText: String?) -> String? 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/TextInputFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextInputFormatter.swift 3 | // 4 | // Created by Oleksandr Orlov on 18.10.2017. 5 | // Copyright © 2017 Oleksandr Orlov. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | /// Interface for formatter of TextInput, that allow change format of text during input 11 | public protocol TextInputFormatter { 12 | 13 | func formatInput( 14 | currentText: String, range: NSRange, replacementString text: String) -> FormattedTextValue 15 | } 16 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/TextNumberFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextNumberFormatter.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 01.02.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol TextNumberFormatter { 12 | func format(_ number: NSNumber) -> String? 13 | } 14 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/TextNumberUnformatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextNumberUnformatter.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol TextNumberUnformatter { 12 | func unformatNumber(_ formattedText: String?) -> NSNumber? 13 | } 14 | -------------------------------------------------------------------------------- /Source/TextFormatter/TextFormatter/TextUnformatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TextUnformatter.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol TextUnformatter { 12 | /** 13 | Method for convert string, that sutisfy current textPattern, into unformatted string 14 | 15 | - Parameters: 16 | - formatted: String to convert 17 | 18 | - Returns: String converted into unformatted 19 | */ 20 | func unformat(_ formattedText: String?) -> String? 21 | } 22 | -------------------------------------------------------------------------------- /Tests/DefaultTextFormatterTests/DefaultTextFormatterTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextFormatterTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class DefaultTextFormatterTests: XCTestCase { 13 | 14 | // "" -> "" 15 | func test1() { 16 | let formatter = DefaultTextFormatter(textPattern: "## ## ##") 17 | let result = formatter.format("") 18 | let expectedResult = "" 19 | XCTAssertEqual(result, expectedResult) 20 | } 21 | 22 | // 123 -> 12 3 23 | func test2() { 24 | let formatter = DefaultTextFormatter(textPattern: "## ## ##") 25 | let result = formatter.format("123") 26 | let expectedResult = "12 3" 27 | XCTAssertEqual(result, expectedResult) 28 | } 29 | 30 | // 123 -> +5 12 3 31 | func test3() { 32 | let formatter = DefaultTextFormatter(textPattern: "+5 ## ## ##") 33 | let result = formatter.format("123") 34 | let expectedResult = "+5 12 3" 35 | XCTAssertEqual(result, expectedResult) 36 | } 37 | 38 | // 123 -> 😊 12 3 39 | func test4() { 40 | let formatter = DefaultTextFormatter(textPattern: "😊 ## ## ##") 41 | let result = formatter.format("123") 42 | let expectedResult = "😊 12 3" 43 | XCTAssertEqual(result, expectedResult) 44 | } 45 | 46 | // nil -> nil 47 | func test5() { 48 | let formatter = DefaultTextFormatter(textPattern: "## ## ##") 49 | let result = formatter.format(nil) 50 | let expectedResult: String? = nil 51 | XCTAssertEqual(result, expectedResult) 52 | } 53 | 54 | // 1234 -> 12 34 55 | func test6() { 56 | let formatter = DefaultTextFormatter(textPattern: "XX XX", patternSymbol: "X") 57 | let result = formatter.format("1234") 58 | let expectedResult = "12 34" 59 | XCTAssertEqual(result, expectedResult) 60 | } 61 | 62 | // #123 -> #1-23 63 | func test7() { 64 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 65 | let result = formatter.format("#123") 66 | let expectedResult = "#1-23" 67 | XCTAssertEqual(result, expectedResult) 68 | } 69 | 70 | // #### -> ##-## 71 | func test8() { 72 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 73 | let result = formatter.format("####") 74 | let expectedResult = "##-##" 75 | XCTAssertEqual(result, expectedResult) 76 | } 77 | 78 | // abcd -> ab-cd 79 | func test9() { 80 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 81 | let result = formatter.format("abcd") 82 | let expectedResult = "ab-cd" 83 | XCTAssertEqual(result, expectedResult) 84 | } 85 | 86 | // a1b2 -> a1-b2 87 | func test10() { 88 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 89 | let result = formatter.format("a1b2") 90 | let expectedResult = "a1-b2" 91 | XCTAssertEqual(result, expectedResult) 92 | } 93 | 94 | func test11() { 95 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 96 | let result = formatter.format("a1#b#2") 97 | let expectedResult = "a1-#b-#2" 98 | XCTAssertEqual(result, expectedResult) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Tests/DefaultTextFormatterTests/DefaultTextFormatterUnformatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextFormatterUnformatTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class DefaultTextFormatterUnformatTests: XCTestCase { 13 | 14 | // 12-34-45 -> 123445 15 | func test1() { 16 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 17 | let result = formatter.unformat("12-34-45") 18 | let expectedResult = "123445" 19 | XCTAssertEqual(result, expectedResult) 20 | } 21 | 22 | // 12 34 -> 1234 23 | func test2() { 24 | let formatter = DefaultTextFormatter(textPattern: "## ## ##") 25 | let result = formatter.unformat("12 34") 26 | let expectedResult = "1234" 27 | XCTAssertEqual(result, expectedResult) 28 | } 29 | 30 | // +5 11 22 31 | func test3() { 32 | let formatter = DefaultTextFormatter(textPattern: "+5 ## ##") 33 | let result = formatter.unformat("+5 11 22") 34 | let expectedResult = "1122" 35 | XCTAssertEqual(result, expectedResult) 36 | } 37 | 38 | // "" -> "" 39 | func test4() { 40 | let formatter = DefaultTextFormatter(textPattern: "##-## ##") 41 | let result = formatter.unformat("") 42 | let expectedResult = "" 43 | XCTAssertEqual(result, expectedResult) 44 | } 45 | 46 | // nil -> nil 47 | func test5() { 48 | let formatter = DefaultTextFormatter(textPattern: "##-## ##") 49 | let result = formatter.unformat(nil) 50 | let expectedResult: String? = nil 51 | XCTAssertEqual(result, expectedResult) 52 | } 53 | 54 | func test6() { 55 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 56 | let result = formatter.unformat("12-##") 57 | let expectedResult = "12##" 58 | XCTAssertEqual(result, expectedResult) 59 | } 60 | 61 | func test7() { 62 | let formatter = DefaultTextFormatter(textPattern: "##-##-##") 63 | let result = formatter.unformat("12-ab") 64 | let expectedResult = "12ab" 65 | XCTAssertEqual(result, expectedResult) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Tests/DefaultTextInputFormatterTests/Format/DefaultTextInputFormatterFormatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextInputFormatterFormatTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 BRANDERSTUDIO. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class DefaultTextInputFormatterFormatTests: XCTestCase { 13 | 14 | // "" -> "" 15 | func test1() { 16 | let formatter = DefaultTextInputFormatter(textPattern: "## ## ##") 17 | let result = formatter.format("") 18 | let expectedResult = "" 19 | XCTAssertEqual(result, expectedResult) 20 | } 21 | 22 | // 123 -> 12 3 23 | func test2() { 24 | let formatter = DefaultTextInputFormatter(textPattern: "## ## ##") 25 | let result = formatter.format("123") 26 | let expectedResult = "12 3" 27 | XCTAssertEqual(result, expectedResult) 28 | } 29 | 30 | // 123 -> +5 12 3 31 | func test3() { 32 | let formatter = DefaultTextInputFormatter(textPattern: "+5 ## ## ##") 33 | let result = formatter.format("123") 34 | let expectedResult = "+5 12 3" 35 | XCTAssertEqual(result, expectedResult) 36 | } 37 | 38 | // 123 -> 😊 12 3 39 | func test4() { 40 | let formatter = DefaultTextInputFormatter(textPattern: "😊 ## ## ##") 41 | let result = formatter.format("123") 42 | let expectedResult = "😊 12 3" 43 | XCTAssertEqual(result, expectedResult) 44 | } 45 | 46 | // nil -> nil 47 | func test5() { 48 | let formatter = DefaultTextInputFormatter(textPattern: "## ## ##") 49 | let result = formatter.format(nil) 50 | let expectedResult: String? = nil 51 | XCTAssertEqual(result, expectedResult) 52 | } 53 | 54 | // 1234 -> 12 34 55 | func test6() { 56 | let formatter = DefaultTextInputFormatter(textPattern: "XX XX", patternSymbol: "X") 57 | let result = formatter.format("1234") 58 | let expectedResult = "12 34" 59 | XCTAssertEqual(result, expectedResult) 60 | } 61 | 62 | // #123 -> #1-23 63 | func test7() { 64 | let formatter = DefaultTextInputFormatter(textPattern: "##-##-##") 65 | let result = formatter.format("#123") 66 | let expectedResult = "#1-23" 67 | XCTAssertEqual(result, expectedResult) 68 | } 69 | 70 | // #### -> ##-## 71 | func test8() { 72 | let formatter = DefaultTextInputFormatter(textPattern: "##-##-##") 73 | let result = formatter.format("####") 74 | let expectedResult = "##-##" 75 | XCTAssertEqual(result, expectedResult) 76 | } 77 | 78 | // abcd -> ab-cd 79 | func test9() { 80 | let formatter = DefaultTextInputFormatter(textPattern: "##-##-##") 81 | let result = formatter.format("abcd") 82 | let expectedResult = "ab-cd" 83 | XCTAssertEqual(result, expectedResult) 84 | } 85 | 86 | // a1b2 -> a1-b2 87 | func test10() { 88 | let formatter = DefaultTextInputFormatter(textPattern: "##-##-##") 89 | let result = formatter.format("a1b2") 90 | let expectedResult = "a1-b2" 91 | XCTAssertEqual(result, expectedResult) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Tests/DefaultTextInputFormatterTests/FormatInput/Insert/AnyFormatKitTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnyFormatKitTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 01.11.2017. 6 | // Copyright © 2017 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class AnyFormatKitTests: XCTestCase { 13 | let phoneNumberFormatter = DefaultTextFormatter(textPattern: "### (###) ##-##-###") 14 | 15 | func testOneSymbolFormatting() { 16 | let expectedString = "3" 17 | let formattedString = phoneNumberFormatter.format("3") 18 | XCTAssert(expectedString == formattedString, "\(expectedString) must be equal to \(String(describing: formattedString))") 19 | } 20 | 21 | func testFullStringFormatting() { 22 | let expectedString = "123 (456) 78-78-789" 23 | let formattedString = phoneNumberFormatter.format("1234567878789") 24 | XCTAssert(expectedString == formattedString, "\(expectedString) must be equal to \(String(describing: formattedString))") 25 | } 26 | 27 | func testOverLengthStringFormatting() { 28 | let expectedString = "123 (456) 78-78-789" 29 | let formattedString = phoneNumberFormatter.format("123456787878900000") 30 | XCTAssert(expectedString == formattedString, "\(expectedString) must be equal to \(String(describing: formattedString))") 31 | } 32 | 33 | func testEmptyStringFormatting() { 34 | let expectedString = "" 35 | let formattedString = phoneNumberFormatter.format("") 36 | XCTAssert(expectedString == formattedString, "\(expectedString) must be equal to \(String(describing: formattedString))") 37 | } 38 | 39 | func testNilStringFormatting() { 40 | let expectedString: String? = nil 41 | let formattedString = phoneNumberFormatter.format(nil) 42 | XCTAssert(expectedString == formattedString, "\(String(describing: expectedString)) must be equal to \(String(describing: formattedString))") 43 | } 44 | 45 | func testHalfStringFormatting() { 46 | let expectedString = "123 (45" 47 | let formattedString = phoneNumberFormatter.format("12345") 48 | XCTAssert(expectedString == formattedString, "\(expectedString) must be equal to \(String(describing: formattedString))") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tests/DefaultTextInputFormatterTests/FormatInput/Insert/DefaultTextInputFormatterPhoneEmojisInputTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextInputFormatterPhoneEmojisInputTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 16.01.2021. 6 | // Copyright © 2021 Orlov Oleksandr. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class DefaultTextInputFormatterPhoneEmojisInputTests: XCTestCase { 13 | 14 | private let formatter = DefaultTextInputFormatter(textPattern: "### (###) ###-##-##") 15 | 16 | // | -> 😊| 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "", 20 | range: NSRange(location: 0, length: 0), 21 | replacementString: "😊") 22 | let expectedResult = FormattedTextValue(formattedText: "😊", caretBeginOffset: 2) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 😊| -> 😊👍| 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "😊", 30 | range: NSRange(location: 2, length: 0), 31 | replacementString: "👍") 32 | let expectedResult = FormattedTextValue(formattedText: "😊👍", caretBeginOffset: 4) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // 😊👍| -> 😊👍🙈| 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "😊👍", 40 | range: NSRange(location: 4, length: 0), 41 | replacementString: "🙈") 42 | let expectedResult = FormattedTextValue(formattedText: "😊👍🙈", caretBeginOffset: 6) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | 46 | // 😊👍🙈| -> 😊👍🙈 (😱| 47 | func test4() { 48 | let actualResult = formatter.formatInput( 49 | currentText: "😊👍🙈", 50 | range: NSRange(location: 6, length: 0), 51 | replacementString: "😱") 52 | let expectedResult = FormattedTextValue(formattedText: "😊👍🙈 (😱", caretBeginOffset: 10) 53 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 54 | } 55 | 56 | // 😊👍🙈 (😱| -> 😊👍🙈 (😱😭| 57 | func test5() { 58 | let actualResult = formatter.formatInput( 59 | currentText: "😊👍🙈 (😱", 60 | range: NSRange(location: 10, length: 0), 61 | replacementString: "😭") 62 | let expectedResult = FormattedTextValue(formattedText: "😊👍🙈 (😱😭", caretBeginOffset: 12) 63 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/DefaultTextInputFormatterTests/FormatInput/Replace/DefaultTextInputFormatter1SymbolReplaceTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextInputFormatter1SymbolReplaceTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 09.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class DefaultTextInputFormatter1SymbolReplaceTests: XCTestCase { 13 | 14 | private let formatter = DefaultTextInputFormatter(textPattern: "## ## ##") 15 | 16 | // 12 3|4| -> 12 30| 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "12 34", 20 | range: NSRange(location: 4, length: 1), 21 | replacementString: "0") 22 | let expectedResult = FormattedTextValue(formattedText: "12 30", caretBeginOffset: 5) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | func test2() { 27 | let actualResult = formatter.formatInput( 28 | currentText: "12 34", 29 | range: NSRange(location: 3, length: 1), 30 | replacementString: "0") 31 | let expectedResult = FormattedTextValue(formattedText: "12 04", caretBeginOffset: 4) 32 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 33 | } 34 | 35 | func test12_34to10_34() { 36 | let actualResult = formatter.formatInput( 37 | currentText: "12 34", 38 | range: NSRange(location: 1, length: 1), 39 | replacementString: "0") 40 | let expectedResult = FormattedTextValue(formattedText: "10 34", caretBeginOffset: 2) 41 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 42 | } 43 | 44 | func test12_34to02_34() { 45 | let actualResult = formatter.formatInput( 46 | currentText: "12 34", 47 | range: NSRange(location: 0, length: 1), 48 | replacementString: "0") 49 | let expectedResult = FormattedTextValue(formattedText: "02 34", caretBeginOffset: 1) 50 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 51 | } 52 | 53 | func test12I_I34to12_03_4() { 54 | let actualResult = formatter.formatInput( 55 | currentText: "12 34", 56 | range: NSRange(location: 2, length: 1), 57 | replacementString: "0") 58 | let expectedResult = FormattedTextValue(formattedText: "12 03 4", caretBeginOffset: 4) 59 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Tests/DefaultTextInputFormatterTests/Unformat/DefaultTextInputUnformattingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultTextInputUnformattingTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class DefaultTextInputUnformattingTests: XCTestCase { 13 | 14 | // +5 123 456 -> 123456 15 | func test1() { 16 | let formatter = DefaultTextInputFormatter(textPattern: "+5 ### ###") 17 | let result = formatter.unformat("+5 123 456") 18 | let expectedResult = "123456" 19 | XCTAssertEqual(result, expectedResult) 20 | } 21 | 22 | // 123 4 -> 1234 23 | func test2() { 24 | let formatter = DefaultTextInputFormatter(textPattern: "### ###") 25 | let result = formatter.unformat("123 4") 26 | let expectedResult = "1234" 27 | XCTAssertEqual(result, expectedResult) 28 | } 29 | 30 | // "" -> "" 31 | func test3() { 32 | let formatter = DefaultTextInputFormatter(textPattern: "### ###") 33 | let result = formatter.unformat("") 34 | let expectedResult = "" 35 | XCTAssertEqual(result, expectedResult) 36 | } 37 | 38 | // nil -> nil 39 | func test4() { 40 | let formatter = DefaultTextInputFormatter(textPattern: "### ###") 41 | let result = formatter.unformat(nil) 42 | let expectedResult: String? = nil 43 | XCTAssertEqual(result, expectedResult) 44 | } 45 | 46 | func test5() { 47 | let formatter = DefaultTextInputFormatter(textPattern: "+5 ### ###") 48 | let result = formatter.unformat("+5 ") 49 | let expectedResult = "" 50 | XCTAssertEqual(result, expectedResult) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/PlaceholderFormatterTests/PlaceholderFormatterFormattingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderFormatterFormattingTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class PlaceholderFormatterFormattingTests: XCTestCase { 13 | 14 | func test1() { 15 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 16 | let result = formatter.format("12345678") 17 | let expectedResult = "1234 5678" 18 | XCTAssertEqual(result, expectedResult) 19 | } 20 | 21 | func test2() { 22 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 23 | let result = formatter.format("12") 24 | let expectedResult = "12## ####" 25 | XCTAssertEqual(result, expectedResult) 26 | } 27 | 28 | func test3() { 29 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 30 | let result = formatter.format("") 31 | let expectedResult = "#### ####" 32 | XCTAssertEqual(result, expectedResult) 33 | } 34 | 35 | func test4() { 36 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 37 | let result = formatter.format(nil) 38 | let expectedResult = "#### ####" 39 | XCTAssertEqual(result, expectedResult) 40 | } 41 | 42 | func test5() { 43 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 44 | let result = formatter.format("1") 45 | let expectedResult = "1### ####" 46 | XCTAssertEqual(result, expectedResult) 47 | } 48 | 49 | func test6() { 50 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 51 | let result = formatter.format("123456789") 52 | let expectedResult = "1234 5678" 53 | XCTAssertEqual(result, expectedResult) 54 | } 55 | 56 | func test7() { 57 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 58 | let result = formatter.format("1234567") 59 | let expectedResult = "1234 567#" 60 | XCTAssertEqual(result, expectedResult) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Tests/PlaceholderFormatterTests/PlaceholderFormatterUnformattingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderFormatterUnformattingTests.swift 3 | // AnyFormatKit 4 | // 5 | // Created by Oleksandr Orlov on 12.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class PlaceholderFormatterUnformattingTests: XCTestCase { 13 | 14 | func test1() { 15 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 16 | let result = formatter.unformat("12## ####") 17 | let expectedResult = "12" 18 | XCTAssertEqual(result, expectedResult) 19 | } 20 | 21 | func test2() { 22 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 23 | let result = formatter.unformat("#### ####") 24 | let expectedResult = "" 25 | XCTAssertEqual(result, expectedResult) 26 | } 27 | 28 | func test3() { 29 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 30 | let result = formatter.unformat("1234 ####") 31 | let expectedResult = "1234" 32 | XCTAssertEqual(result, expectedResult) 33 | } 34 | 35 | func test4() { 36 | let formatter = PlaceholderTextFormatter(textPattern: "#### ####") 37 | let result = formatter.unformat("1234 5###") 38 | let expectedResult = "12345" 39 | XCTAssertEqual(result, expectedResult) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/PlaceholderTextInputFormatterTests/Format/PlaceholderTextInputFormatterFormatTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderTextInputFormatterFormatTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 BRANDERSTUDIO. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class PlaceholderTextInputFormatterFormatTests: XCTestCase { 13 | 14 | func test1() { 15 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 16 | let result = formatter.format("12345678") 17 | let expectedResult = "1234 5678" 18 | XCTAssertEqual(result, expectedResult) 19 | } 20 | 21 | func test2() { 22 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 23 | let result = formatter.format("12") 24 | let expectedResult = "12## ####" 25 | XCTAssertEqual(result, expectedResult) 26 | } 27 | 28 | func test3() { 29 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 30 | let result = formatter.format("") 31 | let expectedResult = "#### ####" 32 | XCTAssertEqual(result, expectedResult) 33 | } 34 | 35 | func test4() { 36 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 37 | let result = formatter.format(nil) 38 | let expectedResult = "#### ####" 39 | XCTAssertEqual(result, expectedResult) 40 | } 41 | 42 | func test5() { 43 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 44 | let result = formatter.format("1") 45 | let expectedResult = "1### ####" 46 | XCTAssertEqual(result, expectedResult) 47 | } 48 | 49 | func test6() { 50 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 51 | let result = formatter.format("123456789") 52 | let expectedResult = "1234 5678" 53 | XCTAssertEqual(result, expectedResult) 54 | } 55 | 56 | func test7() { 57 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 58 | let result = formatter.format("1234567") 59 | let expectedResult = "1234 567#" 60 | XCTAssertEqual(result, expectedResult) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Tests/PlaceholderTextInputFormatterTests/FormatInput/Replace/PlaceholderTextInputFormatterReplace3SymbolsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderTextInputFormatterReplace3SymbolsTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 13.11.2020. 6 | // Copyright © 2020 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class PlaceholderTextInputFormatterReplace3SymbolsTests: XCTestCase { 13 | 14 | // |123| ### -> 789| ### 15 | func test1() { 16 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 17 | let result = formatter.formatInput( 18 | currentText: "123 ###", 19 | range: NSRange(location: 0, length: 3), 20 | replacementString: "789" 21 | ) 22 | let expectedResult = FormattedTextValue(formattedText: "789 ###", caretBeginOffset: 3) 23 | XCTAssertEqual(result, expectedResult) 24 | } 25 | 26 | // |123| 456 -> 789| 456 27 | func test2() { 28 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 29 | let result = formatter.formatInput( 30 | currentText: "123 456", 31 | range: NSRange(location: 0, length: 3), 32 | replacementString: "789" 33 | ) 34 | let expectedResult = FormattedTextValue(formattedText: "789 456", caretBeginOffset: 3) 35 | XCTAssertEqual(result, expectedResult) 36 | } 37 | 38 | // 1|23 |### -> 178 9|## 39 | func test3() { 40 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 41 | let result = formatter.formatInput( 42 | currentText: "123 ###", 43 | range: NSRange(location: 1, length: 3), 44 | replacementString: "789" 45 | ) 46 | let expectedResult = FormattedTextValue(formattedText: "178 9##", caretBeginOffset: 5) 47 | XCTAssertEqual(result, expectedResult) 48 | } 49 | 50 | // 12|3 #|## -> 127 89|# 51 | func test4() { 52 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 53 | let result = formatter.formatInput( 54 | currentText: "123 ###", 55 | range: NSRange(location: 2, length: 3), 56 | replacementString: "789" 57 | ) 58 | let expectedResult = FormattedTextValue(formattedText: "127 89#", caretBeginOffset: 6) 59 | XCTAssertEqual(result, expectedResult) 60 | } 61 | 62 | // 12|3 4|56 -> 127 89|5 63 | func test5() { 64 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 65 | let result = formatter.formatInput( 66 | currentText: "123 456", 67 | range: NSRange(location: 2, length: 3), 68 | replacementString: "789" 69 | ) 70 | let expectedResult = FormattedTextValue(formattedText: "127 895", caretBeginOffset: 6) 71 | XCTAssertEqual(result, expectedResult) 72 | } 73 | 74 | // 123| ##|# -> 123 789| 75 | func test6() { 76 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 77 | let result = formatter.formatInput( 78 | currentText: "123 ###", 79 | range: NSRange(location: 3, length: 3), 80 | replacementString: "789" 81 | ) 82 | let expectedResult = FormattedTextValue(formattedText: "123 789", caretBeginOffset: 7) 83 | XCTAssertEqual(result, expectedResult) 84 | } 85 | 86 | // 123 |###| -> 123 789| 87 | func test7() { 88 | let formatter = PlaceholderTextInputFormatter(textPattern: "### ###") 89 | let result = formatter.formatInput( 90 | currentText: "123 ###", 91 | range: NSRange(location: 4, length: 3), 92 | replacementString: "789" 93 | ) 94 | let expectedResult = FormattedTextValue(formattedText: "123 789", caretBeginOffset: 7) 95 | XCTAssertEqual(result, expectedResult) 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /Tests/PlaceholderTextInputFormatterTests/Unformat/PlaceholderTextInputUnformattingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceholderTextInputUnformattingTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 18.01.2021. 6 | // Copyright © 2021 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class PlaceholderTextInputUnformattingTests: XCTestCase { 13 | 14 | func test1() { 15 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 16 | let result = formatter.unformat("12## ####") 17 | let expectedResult = "12" 18 | XCTAssertEqual(result, expectedResult) 19 | } 20 | 21 | func test2() { 22 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 23 | let result = formatter.unformat("#### ####") 24 | let expectedResult = "" 25 | XCTAssertEqual(result, expectedResult) 26 | } 27 | 28 | func test3() { 29 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 30 | let result = formatter.unformat("1234 ####") 31 | let expectedResult = "1234" 32 | XCTAssertEqual(result, expectedResult) 33 | } 34 | 35 | func test4() { 36 | let formatter = PlaceholderTextInputFormatter(textPattern: "#### ####") 37 | let result = formatter.unformat("1234 5###") 38 | let expectedResult = "12345" 39 | XCTAssertEqual(result, expectedResult) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/SumFormatTests/FormatParsingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormatParsingTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 11/21/17. 6 | // Copyright © 2017 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import AnyFormatKit 11 | 12 | class FormatParsingTests: XCTestCase { 13 | func test5InGroupFormat() { 14 | let formatter = SumTextFormatter(textPattern: "X.XXXXX,XX", patternSymbol: "X") 15 | let initialString = "1234567890123" 16 | let expectedString = "123.45678.90123" 17 | let formattedString = formatter.format(initialString) 18 | XCTAssert(expectedString == formattedString, 19 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 20 | } 21 | 22 | func test3InGroupFormat() { 23 | let formatter = SumTextFormatter(textPattern: "X.XXX,XX", patternSymbol: "X") 24 | let initialString = "1234567890123" 25 | let expectedString = "1.234.567.890.123" 26 | let formattedString = formatter.format(initialString) 27 | XCTAssert(expectedString == formattedString, 28 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 29 | } 30 | 31 | func test1InGroupFormat() { 32 | let formatter = SumTextFormatter(textPattern: "X.X,XX", patternSymbol: "X") 33 | let initialString = "1234567" 34 | let expectedString = "1.2.3.4.5.6.7" 35 | let formattedString = formatter.format(initialString) 36 | XCTAssert(expectedString == formattedString, 37 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 38 | } 39 | 40 | func testGroupingSeparatorParsing() { 41 | let formatter = SumTextFormatter(textPattern: "X.XXX,XX", patternSymbol: "X") 42 | let initialString = "1234567890" 43 | let expectedString = "1.234.567.890" 44 | let formattedString = formatter.format(initialString) 45 | XCTAssert(expectedString == formattedString, 46 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 47 | } 48 | 49 | func testDecimalSeparatorParsing() { 50 | let formatter = SumTextFormatter(textPattern: "X.XXX,XX", patternSymbol: "X") 51 | let initialString = "12345.12" 52 | let expectedString = "12.345,12" 53 | let formattedString = formatter.format(initialString) 54 | XCTAssert(expectedString == formattedString, 55 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 56 | } 57 | 58 | func testPrefixParsing() { 59 | let formatter = SumTextFormatter(textPattern: "Prefix: X.XXX,XX", patternSymbol: "X") 60 | let initialString = "123456789,01" 61 | let expectedString = "Prefix: 123.456.789,01" 62 | let formattedString = formatter.format(initialString) 63 | XCTAssert(expectedString == formattedString, 64 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 65 | } 66 | 67 | func testSufixParsing() { 68 | let formatter = SumTextFormatter(textPattern: "X.XXX,XX <-Sufix", patternSymbol: "X") 69 | let initialString = "1234567" 70 | let expectedString = "1.234.567 <-Sufix" 71 | let formattedString = formatter.format(initialString) 72 | XCTAssert(expectedString == formattedString, 73 | "\(String(describing: formattedString)) must be equal to \(expectedString)") 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/Simple/FormatInput/Delete/SumTextInputFormatterDelete3SymbolsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterDelete3SymbolsTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 15.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterDelete3SymbolsTests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "#,###.##") 15 | 16 | // |12,|345.67 -> |345.67 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "12,345.67", 20 | range: NSRange(location: 0, length: 3), 21 | replacementString: "") 22 | let expectedResult = FormattedTextValue(formattedText: "345.67", caretBeginOffset: 0) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 1|2,3|45.67 -> 1|45.67 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "12,345.67", 30 | range: NSRange(location: 1, length: 3), 31 | replacementString: "") 32 | let expectedResult = FormattedTextValue(formattedText: "145.67", caretBeginOffset: 1) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // 12|,34|5.67 -> 12|5.67 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "12,345.67", 40 | range: NSRange(location: 2, length: 3), 41 | replacementString: "") 42 | let expectedResult = FormattedTextValue(formattedText: "125.67", caretBeginOffset: 2) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | 46 | // 12,|345|.67 -> 12|.67 47 | func test4() { 48 | let actualResult = formatter.formatInput( 49 | currentText: "12,345.67", 50 | range: NSRange(location: 3, length: 3), 51 | replacementString: "") 52 | let expectedResult = FormattedTextValue(formattedText: "12.67", caretBeginOffset: 2) 53 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 54 | } 55 | 56 | // 12,3|45.|67 -> 12,3|67 57 | func test5() { 58 | let actualResult = formatter.formatInput( 59 | currentText: "12,345.67", 60 | range: NSRange(location: 4, length: 3), 61 | replacementString: "") 62 | let expectedResult = FormattedTextValue(formattedText: "12,367", caretBeginOffset: 4) 63 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 64 | } 65 | 66 | // 12,34|5.6|7 -> 12,34|7 67 | func test6() { 68 | let actualResult = formatter.formatInput( 69 | currentText: "12,345.67", 70 | range: NSRange(location: 5, length: 3), 71 | replacementString: "") 72 | let expectedResult = FormattedTextValue(formattedText: "12,347", caretBeginOffset: 5) 73 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 74 | } 75 | 76 | // 12,345|.67| -> 12,345| 77 | func test7() { 78 | let actualResult = formatter.formatInput( 79 | currentText: "12,345.67", 80 | range: NSRange(location: 6, length: 3), 81 | replacementString: "") 82 | let expectedResult = FormattedTextValue(formattedText: "12,345", caretBeginOffset: 6) 83 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/Simple/FormatInput/Insert/SumTextInputFormatterInput0Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterInput0Tests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 19.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterInput0Tests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "#,###.##") 15 | 16 | // 20.| -> 20.0| 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "20.", 20 | range: NSRange(location: 3, length: 0), 21 | replacementString: "0") 22 | let expectedResult = FormattedTextValue(formattedText: "20.0", caretBeginOffset: 4) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 20.0| -> 20.00| 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "20.0", 30 | range: NSRange(location: 4, length: 0), 31 | replacementString: "0") 32 | let expectedResult = FormattedTextValue(formattedText: "20.00", caretBeginOffset: 5) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/Simple/FormatInput/Replace/SumTextInputFormatterReplace3SymbolsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterReplace3SymbolsTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 15.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterReplace3SymbolsTests: XCTestCase { 13 | 14 | let formatter = SumTextInputFormatter(textPattern: "#,###.##") 15 | 16 | // |12,|345.67 -> 809,|345.67 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "12,345.67", 20 | range: NSRange(location: 0, length: 3), 21 | replacementString: "809") 22 | let expectedResult = FormattedTextValue(formattedText: "809,345.67", caretBeginOffset: 4) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 1|2,3|45.67 -> 180,9|45.67 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "12,345.67", 30 | range: NSRange(location: 1, length: 3), 31 | replacementString: "809") 32 | let expectedResult = FormattedTextValue(formattedText: "180,945.67", caretBeginOffset: 5) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // 12|,34|5.67 -> 128,09|5.67 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "12,345.67", 40 | range: NSRange(location: 2, length: 3), 41 | replacementString: "809") 42 | let expectedResult = FormattedTextValue(formattedText: "128,095.67", caretBeginOffset: 6) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | 46 | // 12,|345|.67 -> 12,809|.67 47 | func test4() { 48 | let actualResult = formatter.formatInput( 49 | currentText: "12,345.67", 50 | range: NSRange(location: 3, length: 3), 51 | replacementString: "809") 52 | let expectedResult = FormattedTextValue(formattedText: "12,809.67", caretBeginOffset: 6) 53 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 54 | } 55 | 56 | // 12,3|45.|67 -> 12,380,9|67 57 | func test5() { 58 | let actualResult = formatter.formatInput( 59 | currentText: "12,345.67", 60 | range: NSRange(location: 4, length: 3), 61 | replacementString: "809") 62 | let expectedResult = FormattedTextValue(formattedText: "12,380,967", caretBeginOffset: 8) 63 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 64 | } 65 | 66 | // 12,34|5.6|7 -> 12,348,09|7 67 | func test6() { 68 | let actualResult = formatter.formatInput( 69 | currentText: "12,345.67", 70 | range: NSRange(location: 5, length: 3), 71 | replacementString: "809") 72 | let expectedResult = FormattedTextValue(formattedText: "12,348,097", caretBeginOffset: 9) 73 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 74 | } 75 | 76 | // 12,345|.67| -> 12,345,809| 77 | func test7() { 78 | let actualResult = formatter.formatInput( 79 | currentText: "12,345.67", 80 | range: NSRange(location: 6, length: 3), 81 | replacementString: "809") 82 | let expectedResult = FormattedTextValue(formattedText: "12,345,809", caretBeginOffset: 10) 83 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/WithPrefix/2SymbolsPrefix/Delete/SumTextInputFormatterWith2SymbolsPrefixBy1SymbolErasingTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterWith2SymbolsPrefixBy1SymbolErasingTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 20.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterWith2SymbolsPrefixBy1SymbolErasingTests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "$ #,###.##") 15 | 16 | // $ 12.3|4| -> $ 12.3| 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "$ 12.34", 20 | range: NSRange(location: 6, length: 1), 21 | replacementString: "") 22 | let expectedResult = FormattedTextValue(formattedText: "$ 12.3", caretBeginOffset: 6) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // $ 12.|3| -> $ 12.| 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "$ 12.3", 30 | range: NSRange(location: 5, length: 1), 31 | replacementString: "") 32 | let expectedResult = FormattedTextValue(formattedText: "$ 12.", caretBeginOffset: 5) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // $ 12|.| -> $ 12| 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "$ 12.", 40 | range: NSRange(location: 4, length: 1), 41 | replacementString: "") 42 | let expectedResult = FormattedTextValue(formattedText: "$ 12", caretBeginOffset: 4) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | 46 | // $ 1|2| -> $ 1| 47 | func test4() { 48 | let actualResult = formatter.formatInput( 49 | currentText: "$ 12", 50 | range: NSRange(location: 3, length: 1), 51 | replacementString: "") 52 | let expectedResult = FormattedTextValue(formattedText: "$ 1", caretBeginOffset: 3) 53 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 54 | } 55 | 56 | // $ |1| -> "|" 57 | func test5() { 58 | let actualResult = formatter.formatInput( 59 | currentText: "$ 1", 60 | range: NSRange(location: 2, length: 1), 61 | replacementString: "") 62 | let expectedResult = FormattedTextValue(formattedText: "", caretBeginOffset: 0) 63 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/WithPrefix/2SymbolsPrefix/Insert/SumTextInputFormatterWith2SymbolsPrefixInputTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterWith2SymbolsPrefixInputTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 20.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterWith2SymbolsPrefixInputTests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "$ #,###.##") 15 | 16 | // "|" -> $ 1| 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "", 20 | range: NSRange(location: 0, length: 0), 21 | replacementString: "1") 22 | let expectedResult = FormattedTextValue(formattedText: "$ 1", caretBeginOffset: 3) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // $ 1| -> $ 1. 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "$ 1", 30 | range: NSRange(location: 3, length: 0), 31 | replacementString: ".") 32 | let expectedResult = FormattedTextValue(formattedText: "$ 1.", caretBeginOffset: 4) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // $ 1.| -> $ 1.2 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "$ 1.", 40 | range: NSRange(location: 4, length: 0), 41 | replacementString: "2") 42 | let expectedResult = FormattedTextValue(formattedText: "$ 1.2", caretBeginOffset: 5) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/WithSuffix/1SymbolSuffix/Insert/SumTextInputFormatterWithSuffixInput0Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterWithSuffixInput0Tests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 19.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterWithSuffixInput0Tests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "#,###.## $") 15 | 16 | // 20.| $ -> 20.0| $ 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "20. $", 20 | range: NSRange(location: 3, length: 0), 21 | replacementString: "0") 22 | let expectedResult = FormattedTextValue(formattedText: "20.0 $", caretBeginOffset: 4) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 20.0| $ -> 20.00| $ 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "20.0 $", 30 | range: NSRange(location: 4, length: 0), 31 | replacementString: "0") 32 | let expectedResult = FormattedTextValue(formattedText: "20.00 $", caretBeginOffset: 5) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/SumTextInputFormatterTests/FormatInput/WithSuffix/2SymbolSuffix/Insert/SumTextInputFormatterWith2SymbolsSuffixBy1SymbolInputTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SumTextInputFormatterWith2SymbolsSuffixBy1SymbolInputTests.swift 3 | // AnyFormatKitTests 4 | // 5 | // Created by Oleksandr Orlov on 20.06.2019. 6 | // Copyright © 2019 Oleksandr Orlov. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import AnyFormatKit 11 | 12 | class SumTextInputFormatterWith2SymbolsSuffixBy1SymbolInputTests: XCTestCase { 13 | 14 | private let formatter = SumTextInputFormatter(textPattern: "#,###.## $") 15 | 16 | // "|" -> 1| $ 17 | func test1() { 18 | let actualResult = formatter.formatInput( 19 | currentText: "", 20 | range: NSRange(location: 0, length: 0), 21 | replacementString: "1") 22 | let expectedResult = FormattedTextValue(formattedText: "1 $", caretBeginOffset: 1) 23 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 24 | } 25 | 26 | // 1| $ -> 12| $ 27 | func test2() { 28 | let actualResult = formatter.formatInput( 29 | currentText: "1 $", 30 | range: NSRange(location: 1, length: 0), 31 | replacementString: "2") 32 | let expectedResult = FormattedTextValue(formattedText: "12 $", caretBeginOffset: 2) 33 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 34 | } 35 | 36 | // 12| $ -> 12.| $ 37 | func test3() { 38 | let actualResult = formatter.formatInput( 39 | currentText: "12 $", 40 | range: NSRange(location: 2, length: 0), 41 | replacementString: ".") 42 | let expectedResult = FormattedTextValue(formattedText: "12. $", caretBeginOffset: 3) 43 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 44 | } 45 | 46 | // 12.| $ -> 12.3 $ 47 | func test4() { 48 | let actualResult = formatter.formatInput( 49 | currentText: "12. $", 50 | range: NSRange(location: 3, length: 0), 51 | replacementString: "3") 52 | let expectedResult = FormattedTextValue(formattedText: "12.3 $", caretBeginOffset: 4) 53 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 54 | } 55 | 56 | // 12.3| $ -> 12.34| $ 57 | func test5() { 58 | let actualResult = formatter.formatInput( 59 | currentText: "12.3 $", 60 | range: NSRange(location: 4, length: 0), 61 | replacementString: "4") 62 | let expectedResult = FormattedTextValue(formattedText: "12.34 $", caretBeginOffset: 5) 63 | XCTAssert(actualResult == expectedResult, "\n\(actualResult) must be equal to\n\(expectedResult)") 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /run-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | xcodebuild -project AnyFormatKit.xcodeproj -scheme "AnyFormatKit" -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11 Pro Max,OS=13.3' test 3 | -------------------------------------------------------------------------------- /update_version.rb: -------------------------------------------------------------------------------- 1 | if ARGV.empty? 2 | print("❌ syntax had to be 'ruby update_version.rb version\n'") 3 | exit 4 | end 5 | 6 | $new_version = ARGV[0] 7 | 8 | def update_version(filePath, line_start, line_end) 9 | file_data = File.open(filePath).readlines.map(&:chomp) 10 | 11 | File.open(filePath, "w") { |file| 12 | file_data.each { |line| 13 | edited_line = line 14 | 15 | if line.include? line_start 16 | edited_line = "#{line_start}#{$new_version}#{line_end}" 17 | end 18 | 19 | file.write "#{edited_line}\n" 20 | } 21 | } 22 | end 23 | 24 | 25 | 26 | print("• updating podspec file\n") 27 | 28 | podspec_version_line_start = " s.version = '" 29 | podspec_version_line_end = "'" 30 | 31 | update_version('AnyFormatKit.podspec', podspec_version_line_start, podspec_version_line_end) 32 | 33 | 34 | print("• updating README file\n") 35 | 36 | spm_package_line_start = ' .package(url: "https://github.com/luximetr/AnyFormatKit.git", .upToNextMajor(from: "' 37 | spm_package_line_end = '"))' 38 | 39 | pod_line_start = "pod 'AnyFormatKit', '~> " 40 | pod_line_end = "'" 41 | 42 | update_version('README.md', spm_package_line_start, spm_package_line_end) 43 | update_version('README.md', pod_line_start, pod_line_end) 44 | 45 | 46 | print("• updating xcodeproj file\n") 47 | 48 | xproj_version_line_start = " MARKETING_VERSION = " 49 | xproj_version_line_end = ";" 50 | 51 | update_version('AnyFormatKit.xcodeproj/project.pbxproj', xproj_version_line_start, xproj_version_line_end) 52 | 53 | print "✅ done\n" 54 | 55 | 56 | 57 | --------------------------------------------------------------------------------