├── .gitignore ├── .ruby-gemset ├── .ruby-version ├── .swift-version ├── .swiftlint.yml ├── Assets ├── example_1.gif └── img_logo_jera1.png ├── FIELDS.md ├── Gemfile ├── Gemfile.lock ├── JFB.podspec ├── JFB.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── vitormesquita.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── JFB ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── JFBTests ├── Info.plist └── JFBTests.swift ├── LICENSE ├── Podfile ├── Podfile.lock ├── README.md └── Source ├── Cells └── Material │ ├── MaterialBaseRow │ ├── MaterialBaseField.swift │ └── MaterialBaseRow.swift │ ├── MaterialDate │ ├── MaterialDateCell.swift │ └── MaterialDateRow.swift │ ├── MaterialSubmit │ ├── MaterialSubmitCell.swift │ ├── MaterialSubmitCell.xib │ └── MaterialSubmitRow.swift │ └── MaterialText │ ├── MaterialTextFieldCell.swift │ └── MaterialTextRow.swift ├── Fields ├── JDateField.swift ├── JField.swift ├── JTextField.swift └── JTimeField.swift ├── FormBuilderDelegate.swift ├── FormBuilderViewController.swift ├── Rules └── RuleCPF.swift ├── Sections └── JSection.swift └── Utils ├── Extensions.swift ├── FormEnums.swift └── MaterialAppearence.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | .DS_Store 5 | 6 | ## Build generated 7 | build/ 8 | DerivedData/ 9 | 10 | ## Various settings 11 | *.pbxuser 12 | !default.pbxuser 13 | *.mode1v3 14 | !default.mode1v3 15 | *.mode2v3 16 | !default.mode2v3 17 | *.perspectivev3 18 | !default.perspectivev3 19 | xcuserdata/ 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | *.dSYM.zip 30 | *.dSYM 31 | 32 | ## Playgrounds 33 | timeline.xctimeline 34 | playground.xcworkspace 35 | 36 | # Swift Package Manager 37 | # 38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 39 | # Packages/ 40 | # Package.pins 41 | .build/ 42 | 43 | # CocoaPods 44 | # 45 | # We recommend against adding the Pods directory to your .gitignore. However 46 | # you should judge for yourself, the pros and cons are mentioned at: 47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 48 | # 49 | Pods/ 50 | *.xcworkspace 51 | !Podfile.lock 52 | 53 | # Carthage 54 | # 55 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 56 | # Carthage/Checkouts 57 | 58 | Carthage/Build 59 | 60 | # fastlane 61 | # 62 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 63 | # screenshots whenever they are needed. 64 | # For more information about the recommended setup visit: 65 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 66 | 67 | fastlane/report.xml 68 | fastlane/Preview.html 69 | fastlane/screenshots 70 | fastlane/test_output 71 | 72 | ### 73 | # R.swift 74 | *.generated.swift 75 | 76 | ### 77 | # Gemfile 78 | !Gemfile.lock 79 | -------------------------------------------------------------------------------- /.ruby-gemset: -------------------------------------------------------------------------------- 1 | JFB-ios -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.4.1 -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | 2 | excluded: # paths to ignore during linting. Takes precedence over `included`. 3 | - Pods 4 | - R.generated.swift 5 | 6 | disabled_rules: 7 | - force_cast 8 | - type_name 9 | - force_try 10 | - function_body_length 11 | - nesting 12 | - variable_name 13 | - control_statement 14 | - line_length 15 | - trailing_whitespace 16 | - statement_position 17 | - type_body_length 18 | - todo 19 | - valid_docs 20 | - missing_docs 21 | - file_length 22 | - function_parameter_count 23 | - cyclomatic_complexity 24 | - unused_closure_parameter 25 | - for_where 26 | - unused_optional_binding 27 | - redundant_void_return 28 | - void_return 29 | - vertical_parameter_alignment 30 | - unused_enumerated 31 | - redundant_discardable_let 32 | - empty_parentheses_with_trailing_closure 33 | 34 | opt_in_rules: # some rules are only opt-in 35 | - force_https 36 | - empty_count 37 | - conditional_binding_cascade 38 | - explicit_failure_calls 39 | - explicit_init 40 | - redundant_nil_coalescing 41 | - syntactic_sugar 42 | 43 | line_length: 120 44 | 45 | custom_rules: 46 | explicit_failure_calls: 47 | name: “Avoid asserting ‘false’” 48 | regex: ‘((assert|precondition)\(false)’ 49 | message: “Use assertionFailure() or preconditionFailure() instead.” 50 | severity: warning -------------------------------------------------------------------------------- /Assets/example_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jera/JFB/3a6bbfad3dc385e4e352729289cede765672b158/Assets/example_1.gif -------------------------------------------------------------------------------- /Assets/img_logo_jera1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jera/JFB/3a6bbfad3dc385e4e352729289cede765672b158/Assets/img_logo_jera1.png -------------------------------------------------------------------------------- /FIELDS.md: -------------------------------------------------------------------------------- 1 | ## Fields 2 | 3 | ### JTextField 4 | 5 | JTextField is simple field that can be applied some configs to increase it power. 6 | 7 | ```swift 8 | public init(id: String, 9 | type: TextFieldType, 10 | placeholder: String? = nil, 11 | validations: [ValidationType] = []) { 12 | ... 13 | } 14 | ``` 15 | 16 | - **type**: Set type of field, set field config and mask if needed. 17 | - email 18 | - password 19 | - text 20 | - name 21 | - phone 22 | - cpf 23 | 24 | - 25 | 26 | ### JDateField 27 | 28 | JDateField is a field that `inputView` is `UIDatePicker` just with date (days, months and years) 29 | 30 | ```swift 31 | init(id: String, 32 | placeholder: String? = nil, 33 | validations: [ValidationType] = [], 34 | minDate: Date? = nil, 35 | maxDate: Date? = nil, 36 | displayFormat: String = "dd/MM/yyyy") { 37 | ... 38 | } 39 | ``` 40 | 41 | - **minDate**: Minimum date to set on `UIDatePicker`. 42 | - **maxDate**: Maximum date to set on `UIDatePicker`. 43 | - **displayFormat**: It's a format that value will be showed in field. (Need be a valid format) 44 | 45 | - 46 | 47 | ### JTimeField 48 | 49 | JTimeField is a field that `inputView` is `UIDatePicker` just with time (hours and minutes) 50 | 51 | ```swift 52 | init(id: String, 53 | placeholder: String? = nil, 54 | validations: [ValidationType] = [], 55 | minInterval: Int? = nil) { 56 | ... 57 | } 58 | ``` 59 | 60 | - **minInterval**: Interval in minutes. -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cocoapods', '~> 1.4.0' -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.0) 5 | activesupport (4.2.10) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | atomos (0.1.2) 11 | claide (1.0.2) 12 | cocoapods (1.4.0) 13 | activesupport (>= 4.0.2, < 5) 14 | claide (>= 1.0.2, < 2.0) 15 | cocoapods-core (= 1.4.0) 16 | cocoapods-deintegrate (>= 1.0.2, < 2.0) 17 | cocoapods-downloader (>= 1.1.3, < 2.0) 18 | cocoapods-plugins (>= 1.0.0, < 2.0) 19 | cocoapods-search (>= 1.0.0, < 2.0) 20 | cocoapods-stats (>= 1.0.0, < 2.0) 21 | cocoapods-trunk (>= 1.3.0, < 2.0) 22 | cocoapods-try (>= 1.1.0, < 2.0) 23 | colored2 (~> 3.1) 24 | escape (~> 0.0.4) 25 | fourflusher (~> 2.0.1) 26 | gh_inspector (~> 1.0) 27 | molinillo (~> 0.6.4) 28 | nap (~> 1.0) 29 | ruby-macho (~> 1.1) 30 | xcodeproj (>= 1.5.4, < 2.0) 31 | cocoapods-core (1.4.0) 32 | activesupport (>= 4.0.2, < 6) 33 | fuzzy_match (~> 2.0.4) 34 | nap (~> 1.0) 35 | cocoapods-deintegrate (1.0.2) 36 | cocoapods-downloader (1.2.0) 37 | cocoapods-plugins (1.0.0) 38 | nap 39 | cocoapods-search (1.0.0) 40 | cocoapods-stats (1.0.0) 41 | cocoapods-trunk (1.3.0) 42 | nap (>= 0.8, < 2.0) 43 | netrc (~> 0.11) 44 | cocoapods-try (1.1.0) 45 | colored2 (3.1.2) 46 | concurrent-ruby (1.0.5) 47 | escape (0.0.4) 48 | fourflusher (2.0.1) 49 | fuzzy_match (2.0.4) 50 | gh_inspector (1.1.3) 51 | i18n (0.9.5) 52 | concurrent-ruby (~> 1.0) 53 | minitest (5.11.3) 54 | molinillo (0.6.5) 55 | nanaimo (0.2.5) 56 | nap (1.1.0) 57 | netrc (0.11.0) 58 | ruby-macho (1.1.0) 59 | thread_safe (0.3.6) 60 | tzinfo (1.2.5) 61 | thread_safe (~> 0.1) 62 | xcodeproj (1.5.7) 63 | CFPropertyList (>= 2.3.3, < 4.0) 64 | atomos (~> 0.1.2) 65 | claide (>= 1.0.2, < 2.0) 66 | colored2 (~> 3.1) 67 | nanaimo (~> 0.2.4) 68 | 69 | PLATFORMS 70 | ruby 71 | 72 | DEPENDENCIES 73 | cocoapods (~> 1.4.0) 74 | 75 | BUNDLED WITH 76 | 1.16.0 77 | -------------------------------------------------------------------------------- /JFB.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'JFB' 3 | s.version = '0.1' 4 | s.summary = "Jera's new way to build form quickly and easily" 5 | 6 | s.description = <<-DESC 7 | Jera Form Builder (JFB) bring a new way to build form using *Eureka* enginee 8 | DESC 9 | 10 | s.homepage = 'https://github.com/vitormesquita/JFB' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'Vitor Mesquita' => 'vitor.mesquita09@gmail.com' } 13 | s.source = { :git => 'https://github.com/vitormesquita/JFB.git', :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = '9.0' 16 | 17 | s.default_subspec = "Core" 18 | 19 | s.subspec "Core" do |ss| 20 | ss.source_files = "Source/**/*.swift" 21 | 22 | ss.dependency 'Eureka', '~> 4' 23 | ss.dependency 'Material', '~> 2' 24 | ss.dependency 'NSStringMask', '~> 1.2' 25 | end 26 | 27 | s.resource_bundles = { 28 | 'JFB' => ['Assets/*.png'] 29 | } 30 | 31 | end 32 | -------------------------------------------------------------------------------- /JFB.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4F9A0CCEBAA59F85D419BB22 /* libPods-JFBTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B19E8BEA53660BA7CDE650C /* libPods-JFBTests.a */; }; 11 | 912D4A6E2D7B478C786126FA /* Pods_JFB.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9BE529F2AB7D1B63621C2C38 /* Pods_JFB.framework */; }; 12 | FC083C0E2085673A0026AAF9 /* JTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC083C0D2085673A0026AAF9 /* JTextField.swift */; }; 13 | FC083C1220856E170026AAF9 /* MaterialSubmitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC083C1020856E170026AAF9 /* MaterialSubmitCell.swift */; }; 14 | FC083C1320856E170026AAF9 /* MaterialSubmitCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = FC083C1120856E170026AAF9 /* MaterialSubmitCell.xib */; }; 15 | FC083C1520856F8C0026AAF9 /* MaterialSubmitRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC083C1420856F8C0026AAF9 /* MaterialSubmitRow.swift */; }; 16 | FC083C17208574BB0026AAF9 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC083C16208574BB0026AAF9 /* Extensions.swift */; }; 17 | FC15502420877D6F005AB853 /* MaterialDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC15502320877D6F005AB853 /* MaterialDateCell.swift */; }; 18 | FC15502620877DAA005AB853 /* MaterialDateRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC15502520877DAA005AB853 /* MaterialDateRow.swift */; }; 19 | FC1F25652087CB410045CB97 /* JTimeField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC1F25642087CB410045CB97 /* JTimeField.swift */; }; 20 | FC480E7920863253003C1043 /* FormBuilderDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC480E7820863253003C1043 /* FormBuilderDelegate.swift */; }; 21 | FC480E7C20863453003C1043 /* JField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC480E7B20863453003C1043 /* JField.swift */; }; 22 | FC7B723B20851FE400FADB61 /* FormBuilderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B723A20851FE400FADB61 /* FormBuilderViewController.swift */; }; 23 | FC7B723F208520DE00FADB61 /* FormEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B723E208520DE00FADB61 /* FormEnums.swift */; }; 24 | FC7B72432085295100FADB61 /* MaterialTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B72412085295100FADB61 /* MaterialTextFieldCell.swift */; }; 25 | FC7B7246208535CC00FADB61 /* MaterialTextRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B7245208535CC00FADB61 /* MaterialTextRow.swift */; }; 26 | FC7B7249208546C100FADB61 /* RuleCPF.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC7B7248208546C100FADB61 /* RuleCPF.swift */; }; 27 | FCD50FAC208642F000D7CFF2 /* MaterialBaseRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCD50FAB208642F000D7CFF2 /* MaterialBaseRow.swift */; }; 28 | FCD50FAE2086467300D7CFF2 /* MaterialBaseField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCD50FAD2086467300D7CFF2 /* MaterialBaseField.swift */; }; 29 | FCEFD2572086906F00C0E43D /* JSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEFD2562086906F00C0E43D /* JSection.swift */; }; 30 | FCEFD259208690C200C0E43D /* JDateField.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEFD258208690C200C0E43D /* JDateField.swift */; }; 31 | FCEFD25C20869D2C00C0E43D /* MaterialAppearence.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCEFD25B20869D2C00C0E43D /* MaterialAppearence.swift */; }; 32 | FCF758D52084F650004CFF09 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF758D42084F650004CFF09 /* AppDelegate.swift */; }; 33 | FCF758D72084F650004CFF09 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF758D62084F650004CFF09 /* ViewController.swift */; }; 34 | FCF758DA2084F650004CFF09 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FCF758D82084F650004CFF09 /* Main.storyboard */; }; 35 | FCF758DC2084F651004CFF09 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FCF758DB2084F651004CFF09 /* Assets.xcassets */; }; 36 | FCF758DF2084F651004CFF09 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FCF758DD2084F651004CFF09 /* LaunchScreen.storyboard */; }; 37 | FCF758EA2084F651004CFF09 /* JFBTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FCF758E92084F651004CFF09 /* JFBTests.swift */; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXContainerItemProxy section */ 41 | FCF758E62084F651004CFF09 /* PBXContainerItemProxy */ = { 42 | isa = PBXContainerItemProxy; 43 | containerPortal = FCF758C92084F650004CFF09 /* Project object */; 44 | proxyType = 1; 45 | remoteGlobalIDString = FCF758D02084F650004CFF09; 46 | remoteInfo = JFB; 47 | }; 48 | /* End PBXContainerItemProxy section */ 49 | 50 | /* Begin PBXFileReference section */ 51 | 3B19E8BEA53660BA7CDE650C /* libPods-JFBTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-JFBTests.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 52 | 41B9C00D91AD3F2510C003BB /* Pods-JFB.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JFB.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JFB/Pods-JFB.debug.xcconfig"; sourceTree = ""; }; 53 | 940F62BA8C01ECCE2574DC0D /* Pods-JFBTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JFBTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JFBTests/Pods-JFBTests.debug.xcconfig"; sourceTree = ""; }; 54 | 9BE529F2AB7D1B63621C2C38 /* Pods_JFB.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JFB.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | B8C1CFF3BB059E919B8DA2F0 /* Pods-JFBTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JFBTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JFBTests/Pods-JFBTests.release.xcconfig"; sourceTree = ""; }; 56 | C7639950243EFB9A0710940A /* Pods-JFB.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JFB.release.xcconfig"; path = "Pods/Target Support Files/Pods-JFB/Pods-JFB.release.xcconfig"; sourceTree = ""; }; 57 | FC083C0D2085673A0026AAF9 /* JTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JTextField.swift; sourceTree = ""; }; 58 | FC083C1020856E170026AAF9 /* MaterialSubmitCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialSubmitCell.swift; sourceTree = ""; }; 59 | FC083C1120856E170026AAF9 /* MaterialSubmitCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MaterialSubmitCell.xib; sourceTree = ""; }; 60 | FC083C1420856F8C0026AAF9 /* MaterialSubmitRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialSubmitRow.swift; sourceTree = ""; }; 61 | FC083C16208574BB0026AAF9 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 62 | FC15502320877D6F005AB853 /* MaterialDateCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialDateCell.swift; sourceTree = ""; }; 63 | FC15502520877DAA005AB853 /* MaterialDateRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialDateRow.swift; sourceTree = ""; }; 64 | FC1F25642087CB410045CB97 /* JTimeField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JTimeField.swift; sourceTree = ""; }; 65 | FC480E7820863253003C1043 /* FormBuilderDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormBuilderDelegate.swift; sourceTree = ""; }; 66 | FC480E7B20863453003C1043 /* JField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JField.swift; sourceTree = ""; }; 67 | FC7B723A20851FE400FADB61 /* FormBuilderViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormBuilderViewController.swift; sourceTree = ""; }; 68 | FC7B723E208520DE00FADB61 /* FormEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormEnums.swift; sourceTree = ""; }; 69 | FC7B72412085295100FADB61 /* MaterialTextFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialTextFieldCell.swift; sourceTree = ""; }; 70 | FC7B7245208535CC00FADB61 /* MaterialTextRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialTextRow.swift; sourceTree = ""; }; 71 | FC7B7248208546C100FADB61 /* RuleCPF.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleCPF.swift; sourceTree = ""; }; 72 | FCD50FAB208642F000D7CFF2 /* MaterialBaseRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialBaseRow.swift; sourceTree = ""; }; 73 | FCD50FAD2086467300D7CFF2 /* MaterialBaseField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialBaseField.swift; sourceTree = ""; }; 74 | FCEFD2562086906F00C0E43D /* JSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSection.swift; sourceTree = ""; }; 75 | FCEFD258208690C200C0E43D /* JDateField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JDateField.swift; sourceTree = ""; }; 76 | FCEFD25B20869D2C00C0E43D /* MaterialAppearence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaterialAppearence.swift; sourceTree = ""; }; 77 | FCF758D12084F650004CFF09 /* JFB.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JFB.app; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | FCF758D42084F650004CFF09 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 79 | FCF758D62084F650004CFF09 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 80 | FCF758D92084F650004CFF09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 81 | FCF758DB2084F651004CFF09 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 82 | FCF758DE2084F651004CFF09 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 83 | FCF758E02084F651004CFF09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | FCF758E52084F651004CFF09 /* JFBTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JFBTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | FCF758E92084F651004CFF09 /* JFBTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JFBTests.swift; sourceTree = ""; }; 86 | FCF758EB2084F651004CFF09 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | FCF758CE2084F650004CFF09 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 912D4A6E2D7B478C786126FA /* Pods_JFB.framework in Frameworks */, 95 | ); 96 | runOnlyForDeploymentPostprocessing = 0; 97 | }; 98 | FCF758E22084F651004CFF09 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | 4F9A0CCEBAA59F85D419BB22 /* libPods-JFBTests.a in Frameworks */, 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 2F7B9BEC63B6EEEC027B7B0B /* Pods */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 41B9C00D91AD3F2510C003BB /* Pods-JFB.debug.xcconfig */, 113 | C7639950243EFB9A0710940A /* Pods-JFB.release.xcconfig */, 114 | 940F62BA8C01ECCE2574DC0D /* Pods-JFBTests.debug.xcconfig */, 115 | B8C1CFF3BB059E919B8DA2F0 /* Pods-JFBTests.release.xcconfig */, 116 | ); 117 | name = Pods; 118 | sourceTree = ""; 119 | }; 120 | BC1B95C7DF1E41B69FBC978E /* Frameworks */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 9BE529F2AB7D1B63621C2C38 /* Pods_JFB.framework */, 124 | 3B19E8BEA53660BA7CDE650C /* libPods-JFBTests.a */, 125 | ); 126 | name = Frameworks; 127 | sourceTree = ""; 128 | }; 129 | FC083C07208561440026AAF9 /* MaterialText */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | FC7B7245208535CC00FADB61 /* MaterialTextRow.swift */, 133 | FC7B72412085295100FADB61 /* MaterialTextFieldCell.swift */, 134 | ); 135 | path = MaterialText; 136 | sourceTree = ""; 137 | }; 138 | FC083C0F20856DD70026AAF9 /* MaterialSubmit */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | FC083C1420856F8C0026AAF9 /* MaterialSubmitRow.swift */, 142 | FC083C1020856E170026AAF9 /* MaterialSubmitCell.swift */, 143 | FC083C1120856E170026AAF9 /* MaterialSubmitCell.xib */, 144 | ); 145 | path = MaterialSubmit; 146 | sourceTree = ""; 147 | }; 148 | FC15502120877CC2005AB853 /* Material */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | FCD50FAA208642D100D7CFF2 /* MaterialBaseRow */, 152 | FC083C07208561440026AAF9 /* MaterialText */, 153 | FC15502220877D4D005AB853 /* MaterialDate */, 154 | FC083C0F20856DD70026AAF9 /* MaterialSubmit */, 155 | ); 156 | path = Material; 157 | sourceTree = ""; 158 | }; 159 | FC15502220877D4D005AB853 /* MaterialDate */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | FC15502520877DAA005AB853 /* MaterialDateRow.swift */, 163 | FC15502320877D6F005AB853 /* MaterialDateCell.swift */, 164 | ); 165 | path = MaterialDate; 166 | sourceTree = ""; 167 | }; 168 | FC480E7A2086343D003C1043 /* Fields */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | FC480E7B20863453003C1043 /* JField.swift */, 172 | FC083C0D2085673A0026AAF9 /* JTextField.swift */, 173 | FCEFD258208690C200C0E43D /* JDateField.swift */, 174 | FC1F25642087CB410045CB97 /* JTimeField.swift */, 175 | ); 176 | path = Fields; 177 | sourceTree = ""; 178 | }; 179 | FC7B723920851F9800FADB61 /* Source */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | FCEFD25A20869D1C00C0E43D /* Utils */, 183 | FC7B7247208546B500FADB61 /* Rules */, 184 | FCEFD2552086900B00C0E43D /* Sections */, 185 | FC480E7A2086343D003C1043 /* Fields */, 186 | FC7B72402085291E00FADB61 /* Cells */, 187 | FC480E7820863253003C1043 /* FormBuilderDelegate.swift */, 188 | FC7B723A20851FE400FADB61 /* FormBuilderViewController.swift */, 189 | ); 190 | path = Source; 191 | sourceTree = ""; 192 | }; 193 | FC7B72402085291E00FADB61 /* Cells */ = { 194 | isa = PBXGroup; 195 | children = ( 196 | FC15502120877CC2005AB853 /* Material */, 197 | ); 198 | path = Cells; 199 | sourceTree = ""; 200 | }; 201 | FC7B7247208546B500FADB61 /* Rules */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | FC7B7248208546C100FADB61 /* RuleCPF.swift */, 205 | ); 206 | path = Rules; 207 | sourceTree = ""; 208 | }; 209 | FCD50FAA208642D100D7CFF2 /* MaterialBaseRow */ = { 210 | isa = PBXGroup; 211 | children = ( 212 | FCD50FAB208642F000D7CFF2 /* MaterialBaseRow.swift */, 213 | FCD50FAD2086467300D7CFF2 /* MaterialBaseField.swift */, 214 | ); 215 | path = MaterialBaseRow; 216 | sourceTree = ""; 217 | }; 218 | FCEFD2552086900B00C0E43D /* Sections */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | FCEFD2562086906F00C0E43D /* JSection.swift */, 222 | ); 223 | path = Sections; 224 | sourceTree = ""; 225 | }; 226 | FCEFD25A20869D1C00C0E43D /* Utils */ = { 227 | isa = PBXGroup; 228 | children = ( 229 | FC7B723E208520DE00FADB61 /* FormEnums.swift */, 230 | FC083C16208574BB0026AAF9 /* Extensions.swift */, 231 | FCEFD25B20869D2C00C0E43D /* MaterialAppearence.swift */, 232 | ); 233 | path = Utils; 234 | sourceTree = ""; 235 | }; 236 | FCF758C82084F650004CFF09 = { 237 | isa = PBXGroup; 238 | children = ( 239 | FC7B723920851F9800FADB61 /* Source */, 240 | FCF758D32084F650004CFF09 /* JFB */, 241 | FCF758E82084F651004CFF09 /* JFBTests */, 242 | FCF758D22084F650004CFF09 /* Products */, 243 | 2F7B9BEC63B6EEEC027B7B0B /* Pods */, 244 | BC1B95C7DF1E41B69FBC978E /* Frameworks */, 245 | ); 246 | sourceTree = ""; 247 | }; 248 | FCF758D22084F650004CFF09 /* Products */ = { 249 | isa = PBXGroup; 250 | children = ( 251 | FCF758D12084F650004CFF09 /* JFB.app */, 252 | FCF758E52084F651004CFF09 /* JFBTests.xctest */, 253 | ); 254 | name = Products; 255 | sourceTree = ""; 256 | }; 257 | FCF758D32084F650004CFF09 /* JFB */ = { 258 | isa = PBXGroup; 259 | children = ( 260 | FCF758D62084F650004CFF09 /* ViewController.swift */, 261 | FCF758D42084F650004CFF09 /* AppDelegate.swift */, 262 | FCF758D82084F650004CFF09 /* Main.storyboard */, 263 | FCF758DD2084F651004CFF09 /* LaunchScreen.storyboard */, 264 | FCF758DB2084F651004CFF09 /* Assets.xcassets */, 265 | FCF758E02084F651004CFF09 /* Info.plist */, 266 | ); 267 | path = JFB; 268 | sourceTree = ""; 269 | }; 270 | FCF758E82084F651004CFF09 /* JFBTests */ = { 271 | isa = PBXGroup; 272 | children = ( 273 | FCF758E92084F651004CFF09 /* JFBTests.swift */, 274 | FCF758EB2084F651004CFF09 /* Info.plist */, 275 | ); 276 | path = JFBTests; 277 | sourceTree = ""; 278 | }; 279 | /* End PBXGroup section */ 280 | 281 | /* Begin PBXNativeTarget section */ 282 | FCF758D02084F650004CFF09 /* JFB */ = { 283 | isa = PBXNativeTarget; 284 | buildConfigurationList = FCF758EE2084F651004CFF09 /* Build configuration list for PBXNativeTarget "JFB" */; 285 | buildPhases = ( 286 | CCC1CE4D056BEA6A3B883577 /* [CP] Check Pods Manifest.lock */, 287 | FCF758CD2084F650004CFF09 /* Sources */, 288 | FCF758CE2084F650004CFF09 /* Frameworks */, 289 | FCF758CF2084F650004CFF09 /* Resources */, 290 | C6DC9256815BE5D65B19D365 /* [CP] Embed Pods Frameworks */, 291 | 23B25BD97063490B334C70BA /* [CP] Copy Pods Resources */, 292 | FC7B72332084FD5800FADB61 /* ShellScript */, 293 | ); 294 | buildRules = ( 295 | ); 296 | dependencies = ( 297 | ); 298 | name = JFB; 299 | productName = JFB; 300 | productReference = FCF758D12084F650004CFF09 /* JFB.app */; 301 | productType = "com.apple.product-type.application"; 302 | }; 303 | FCF758E42084F651004CFF09 /* JFBTests */ = { 304 | isa = PBXNativeTarget; 305 | buildConfigurationList = FCF758F12084F651004CFF09 /* Build configuration list for PBXNativeTarget "JFBTests" */; 306 | buildPhases = ( 307 | A41497DCBDC62A769E480501 /* [CP] Check Pods Manifest.lock */, 308 | FCF758E12084F651004CFF09 /* Sources */, 309 | FCF758E22084F651004CFF09 /* Frameworks */, 310 | FCF758E32084F651004CFF09 /* Resources */, 311 | EBF0B6E42588347D806EB138 /* [CP] Embed Pods Frameworks */, 312 | 551B255AE1765744BAA51341 /* [CP] Copy Pods Resources */, 313 | ); 314 | buildRules = ( 315 | ); 316 | dependencies = ( 317 | FCF758E72084F651004CFF09 /* PBXTargetDependency */, 318 | ); 319 | name = JFBTests; 320 | productName = JFBTests; 321 | productReference = FCF758E52084F651004CFF09 /* JFBTests.xctest */; 322 | productType = "com.apple.product-type.bundle.unit-test"; 323 | }; 324 | /* End PBXNativeTarget section */ 325 | 326 | /* Begin PBXProject section */ 327 | FCF758C92084F650004CFF09 /* Project object */ = { 328 | isa = PBXProject; 329 | attributes = { 330 | LastSwiftUpdateCheck = 0930; 331 | LastUpgradeCheck = 0930; 332 | ORGANIZATIONNAME = Jera; 333 | TargetAttributes = { 334 | FCF758D02084F650004CFF09 = { 335 | CreatedOnToolsVersion = 9.3; 336 | }; 337 | FCF758E42084F651004CFF09 = { 338 | CreatedOnToolsVersion = 9.3; 339 | TestTargetID = FCF758D02084F650004CFF09; 340 | }; 341 | }; 342 | }; 343 | buildConfigurationList = FCF758CC2084F650004CFF09 /* Build configuration list for PBXProject "JFB" */; 344 | compatibilityVersion = "Xcode 9.3"; 345 | developmentRegion = en; 346 | hasScannedForEncodings = 0; 347 | knownRegions = ( 348 | en, 349 | Base, 350 | ); 351 | mainGroup = FCF758C82084F650004CFF09; 352 | productRefGroup = FCF758D22084F650004CFF09 /* Products */; 353 | projectDirPath = ""; 354 | projectRoot = ""; 355 | targets = ( 356 | FCF758D02084F650004CFF09 /* JFB */, 357 | FCF758E42084F651004CFF09 /* JFBTests */, 358 | ); 359 | }; 360 | /* End PBXProject section */ 361 | 362 | /* Begin PBXResourcesBuildPhase section */ 363 | FCF758CF2084F650004CFF09 /* Resources */ = { 364 | isa = PBXResourcesBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | FCF758DF2084F651004CFF09 /* LaunchScreen.storyboard in Resources */, 368 | FC083C1320856E170026AAF9 /* MaterialSubmitCell.xib in Resources */, 369 | FCF758DC2084F651004CFF09 /* Assets.xcassets in Resources */, 370 | FCF758DA2084F650004CFF09 /* Main.storyboard in Resources */, 371 | ); 372 | runOnlyForDeploymentPostprocessing = 0; 373 | }; 374 | FCF758E32084F651004CFF09 /* Resources */ = { 375 | isa = PBXResourcesBuildPhase; 376 | buildActionMask = 2147483647; 377 | files = ( 378 | ); 379 | runOnlyForDeploymentPostprocessing = 0; 380 | }; 381 | /* End PBXResourcesBuildPhase section */ 382 | 383 | /* Begin PBXShellScriptBuildPhase section */ 384 | 23B25BD97063490B334C70BA /* [CP] Copy Pods Resources */ = { 385 | isa = PBXShellScriptBuildPhase; 386 | buildActionMask = 2147483647; 387 | files = ( 388 | ); 389 | inputPaths = ( 390 | ); 391 | name = "[CP] Copy Pods Resources"; 392 | outputPaths = ( 393 | ); 394 | runOnlyForDeploymentPostprocessing = 0; 395 | shellPath = /bin/sh; 396 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JFB/Pods-JFB-resources.sh\"\n"; 397 | showEnvVarsInLog = 0; 398 | }; 399 | 551B255AE1765744BAA51341 /* [CP] Copy Pods Resources */ = { 400 | isa = PBXShellScriptBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | ); 404 | inputPaths = ( 405 | ); 406 | name = "[CP] Copy Pods Resources"; 407 | outputPaths = ( 408 | ); 409 | runOnlyForDeploymentPostprocessing = 0; 410 | shellPath = /bin/sh; 411 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JFBTests/Pods-JFBTests-resources.sh\"\n"; 412 | showEnvVarsInLog = 0; 413 | }; 414 | A41497DCBDC62A769E480501 /* [CP] Check Pods Manifest.lock */ = { 415 | isa = PBXShellScriptBuildPhase; 416 | buildActionMask = 2147483647; 417 | files = ( 418 | ); 419 | inputPaths = ( 420 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 421 | "${PODS_ROOT}/Manifest.lock", 422 | ); 423 | name = "[CP] Check Pods Manifest.lock"; 424 | outputPaths = ( 425 | "$(DERIVED_FILE_DIR)/Pods-JFBTests-checkManifestLockResult.txt", 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | shellPath = /bin/sh; 429 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 430 | showEnvVarsInLog = 0; 431 | }; 432 | C6DC9256815BE5D65B19D365 /* [CP] Embed Pods Frameworks */ = { 433 | isa = PBXShellScriptBuildPhase; 434 | buildActionMask = 2147483647; 435 | files = ( 436 | ); 437 | inputPaths = ( 438 | "${SRCROOT}/Pods/Target Support Files/Pods-JFB/Pods-JFB-frameworks.sh", 439 | "${BUILT_PRODUCTS_DIR}/Eureka/Eureka.framework", 440 | "${BUILT_PRODUCTS_DIR}/Material/Material.framework", 441 | "${BUILT_PRODUCTS_DIR}/Motion/Motion.framework", 442 | "${BUILT_PRODUCTS_DIR}/NSStringMask/NSStringMask.framework", 443 | ); 444 | name = "[CP] Embed Pods Frameworks"; 445 | outputPaths = ( 446 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Eureka.framework", 447 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Material.framework", 448 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Motion.framework", 449 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSStringMask.framework", 450 | ); 451 | runOnlyForDeploymentPostprocessing = 0; 452 | shellPath = /bin/sh; 453 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JFB/Pods-JFB-frameworks.sh\"\n"; 454 | showEnvVarsInLog = 0; 455 | }; 456 | CCC1CE4D056BEA6A3B883577 /* [CP] Check Pods Manifest.lock */ = { 457 | isa = PBXShellScriptBuildPhase; 458 | buildActionMask = 2147483647; 459 | files = ( 460 | ); 461 | inputPaths = ( 462 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 463 | "${PODS_ROOT}/Manifest.lock", 464 | ); 465 | name = "[CP] Check Pods Manifest.lock"; 466 | outputPaths = ( 467 | "$(DERIVED_FILE_DIR)/Pods-JFB-checkManifestLockResult.txt", 468 | ); 469 | runOnlyForDeploymentPostprocessing = 0; 470 | shellPath = /bin/sh; 471 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 472 | showEnvVarsInLog = 0; 473 | }; 474 | EBF0B6E42588347D806EB138 /* [CP] Embed Pods Frameworks */ = { 475 | isa = PBXShellScriptBuildPhase; 476 | buildActionMask = 2147483647; 477 | files = ( 478 | ); 479 | inputPaths = ( 480 | ); 481 | name = "[CP] Embed Pods Frameworks"; 482 | outputPaths = ( 483 | ); 484 | runOnlyForDeploymentPostprocessing = 0; 485 | shellPath = /bin/sh; 486 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JFBTests/Pods-JFBTests-frameworks.sh\"\n"; 487 | showEnvVarsInLog = 0; 488 | }; 489 | FC7B72332084FD5800FADB61 /* ShellScript */ = { 490 | isa = PBXShellScriptBuildPhase; 491 | buildActionMask = 2147483647; 492 | files = ( 493 | ); 494 | inputPaths = ( 495 | ); 496 | outputPaths = ( 497 | ); 498 | runOnlyForDeploymentPostprocessing = 0; 499 | shellPath = /bin/sh; 500 | shellScript = "\"${PODS_ROOT}/SwiftLint/swiftlint\""; 501 | }; 502 | /* End PBXShellScriptBuildPhase section */ 503 | 504 | /* Begin PBXSourcesBuildPhase section */ 505 | FCF758CD2084F650004CFF09 /* Sources */ = { 506 | isa = PBXSourcesBuildPhase; 507 | buildActionMask = 2147483647; 508 | files = ( 509 | FCF758D72084F650004CFF09 /* ViewController.swift in Sources */, 510 | FC083C0E2085673A0026AAF9 /* JTextField.swift in Sources */, 511 | FC480E7C20863453003C1043 /* JField.swift in Sources */, 512 | FCEFD259208690C200C0E43D /* JDateField.swift in Sources */, 513 | FC480E7920863253003C1043 /* FormBuilderDelegate.swift in Sources */, 514 | FC15502620877DAA005AB853 /* MaterialDateRow.swift in Sources */, 515 | FC15502420877D6F005AB853 /* MaterialDateCell.swift in Sources */, 516 | FC083C1220856E170026AAF9 /* MaterialSubmitCell.swift in Sources */, 517 | FC7B7249208546C100FADB61 /* RuleCPF.swift in Sources */, 518 | FCF758D52084F650004CFF09 /* AppDelegate.swift in Sources */, 519 | FC083C1520856F8C0026AAF9 /* MaterialSubmitRow.swift in Sources */, 520 | FCEFD2572086906F00C0E43D /* JSection.swift in Sources */, 521 | FC1F25652087CB410045CB97 /* JTimeField.swift in Sources */, 522 | FCEFD25C20869D2C00C0E43D /* MaterialAppearence.swift in Sources */, 523 | FCD50FAC208642F000D7CFF2 /* MaterialBaseRow.swift in Sources */, 524 | FC7B72432085295100FADB61 /* MaterialTextFieldCell.swift in Sources */, 525 | FC7B723F208520DE00FADB61 /* FormEnums.swift in Sources */, 526 | FC7B723B20851FE400FADB61 /* FormBuilderViewController.swift in Sources */, 527 | FCD50FAE2086467300D7CFF2 /* MaterialBaseField.swift in Sources */, 528 | FC083C17208574BB0026AAF9 /* Extensions.swift in Sources */, 529 | FC7B7246208535CC00FADB61 /* MaterialTextRow.swift in Sources */, 530 | ); 531 | runOnlyForDeploymentPostprocessing = 0; 532 | }; 533 | FCF758E12084F651004CFF09 /* Sources */ = { 534 | isa = PBXSourcesBuildPhase; 535 | buildActionMask = 2147483647; 536 | files = ( 537 | FCF758EA2084F651004CFF09 /* JFBTests.swift in Sources */, 538 | ); 539 | runOnlyForDeploymentPostprocessing = 0; 540 | }; 541 | /* End PBXSourcesBuildPhase section */ 542 | 543 | /* Begin PBXTargetDependency section */ 544 | FCF758E72084F651004CFF09 /* PBXTargetDependency */ = { 545 | isa = PBXTargetDependency; 546 | target = FCF758D02084F650004CFF09 /* JFB */; 547 | targetProxy = FCF758E62084F651004CFF09 /* PBXContainerItemProxy */; 548 | }; 549 | /* End PBXTargetDependency section */ 550 | 551 | /* Begin PBXVariantGroup section */ 552 | FCF758D82084F650004CFF09 /* Main.storyboard */ = { 553 | isa = PBXVariantGroup; 554 | children = ( 555 | FCF758D92084F650004CFF09 /* Base */, 556 | ); 557 | name = Main.storyboard; 558 | sourceTree = ""; 559 | }; 560 | FCF758DD2084F651004CFF09 /* LaunchScreen.storyboard */ = { 561 | isa = PBXVariantGroup; 562 | children = ( 563 | FCF758DE2084F651004CFF09 /* Base */, 564 | ); 565 | name = LaunchScreen.storyboard; 566 | sourceTree = ""; 567 | }; 568 | /* End PBXVariantGroup section */ 569 | 570 | /* Begin XCBuildConfiguration section */ 571 | FCF758EC2084F651004CFF09 /* Debug */ = { 572 | isa = XCBuildConfiguration; 573 | buildSettings = { 574 | ALWAYS_SEARCH_USER_PATHS = NO; 575 | CLANG_ANALYZER_NONNULL = YES; 576 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 577 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 578 | CLANG_CXX_LIBRARY = "libc++"; 579 | CLANG_ENABLE_MODULES = YES; 580 | CLANG_ENABLE_OBJC_ARC = YES; 581 | CLANG_ENABLE_OBJC_WEAK = YES; 582 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 583 | CLANG_WARN_BOOL_CONVERSION = YES; 584 | CLANG_WARN_COMMA = YES; 585 | CLANG_WARN_CONSTANT_CONVERSION = YES; 586 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 587 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 588 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 589 | CLANG_WARN_EMPTY_BODY = YES; 590 | CLANG_WARN_ENUM_CONVERSION = YES; 591 | CLANG_WARN_INFINITE_RECURSION = YES; 592 | CLANG_WARN_INT_CONVERSION = YES; 593 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 594 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 595 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 596 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 597 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 598 | CLANG_WARN_STRICT_PROTOTYPES = YES; 599 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 600 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 601 | CLANG_WARN_UNREACHABLE_CODE = YES; 602 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 603 | CODE_SIGN_IDENTITY = "iPhone Developer"; 604 | COPY_PHASE_STRIP = NO; 605 | DEBUG_INFORMATION_FORMAT = dwarf; 606 | ENABLE_STRICT_OBJC_MSGSEND = YES; 607 | ENABLE_TESTABILITY = YES; 608 | GCC_C_LANGUAGE_STANDARD = gnu11; 609 | GCC_DYNAMIC_NO_PIC = NO; 610 | GCC_NO_COMMON_BLOCKS = YES; 611 | GCC_OPTIMIZATION_LEVEL = 0; 612 | GCC_PREPROCESSOR_DEFINITIONS = ( 613 | "DEBUG=1", 614 | "$(inherited)", 615 | ); 616 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 617 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 618 | GCC_WARN_UNDECLARED_SELECTOR = YES; 619 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 620 | GCC_WARN_UNUSED_FUNCTION = YES; 621 | GCC_WARN_UNUSED_VARIABLE = YES; 622 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 623 | MTL_ENABLE_DEBUG_INFO = YES; 624 | ONLY_ACTIVE_ARCH = YES; 625 | SDKROOT = iphoneos; 626 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 627 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 628 | }; 629 | name = Debug; 630 | }; 631 | FCF758ED2084F651004CFF09 /* Release */ = { 632 | isa = XCBuildConfiguration; 633 | buildSettings = { 634 | ALWAYS_SEARCH_USER_PATHS = NO; 635 | CLANG_ANALYZER_NONNULL = YES; 636 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 637 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 638 | CLANG_CXX_LIBRARY = "libc++"; 639 | CLANG_ENABLE_MODULES = YES; 640 | CLANG_ENABLE_OBJC_ARC = YES; 641 | CLANG_ENABLE_OBJC_WEAK = YES; 642 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 643 | CLANG_WARN_BOOL_CONVERSION = YES; 644 | CLANG_WARN_COMMA = YES; 645 | CLANG_WARN_CONSTANT_CONVERSION = YES; 646 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 647 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 648 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 649 | CLANG_WARN_EMPTY_BODY = YES; 650 | CLANG_WARN_ENUM_CONVERSION = YES; 651 | CLANG_WARN_INFINITE_RECURSION = YES; 652 | CLANG_WARN_INT_CONVERSION = YES; 653 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 654 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 655 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 656 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 657 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 658 | CLANG_WARN_STRICT_PROTOTYPES = YES; 659 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 660 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 661 | CLANG_WARN_UNREACHABLE_CODE = YES; 662 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 663 | CODE_SIGN_IDENTITY = "iPhone Developer"; 664 | COPY_PHASE_STRIP = NO; 665 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 666 | ENABLE_NS_ASSERTIONS = NO; 667 | ENABLE_STRICT_OBJC_MSGSEND = YES; 668 | GCC_C_LANGUAGE_STANDARD = gnu11; 669 | GCC_NO_COMMON_BLOCKS = YES; 670 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 671 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 672 | GCC_WARN_UNDECLARED_SELECTOR = YES; 673 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 674 | GCC_WARN_UNUSED_FUNCTION = YES; 675 | GCC_WARN_UNUSED_VARIABLE = YES; 676 | IPHONEOS_DEPLOYMENT_TARGET = 11.3; 677 | MTL_ENABLE_DEBUG_INFO = NO; 678 | SDKROOT = iphoneos; 679 | SWIFT_COMPILATION_MODE = wholemodule; 680 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 681 | VALIDATE_PRODUCT = YES; 682 | }; 683 | name = Release; 684 | }; 685 | FCF758EF2084F651004CFF09 /* Debug */ = { 686 | isa = XCBuildConfiguration; 687 | baseConfigurationReference = 41B9C00D91AD3F2510C003BB /* Pods-JFB.debug.xcconfig */; 688 | buildSettings = { 689 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 690 | CODE_SIGN_STYLE = Automatic; 691 | INFOPLIST_FILE = JFB/Info.plist; 692 | LD_RUNPATH_SEARCH_PATHS = ( 693 | "$(inherited)", 694 | "@executable_path/Frameworks", 695 | ); 696 | PRODUCT_BUNDLE_IDENTIFIER = br.com.jera.JFB; 697 | PRODUCT_NAME = "$(TARGET_NAME)"; 698 | SWIFT_VERSION = 4.0; 699 | TARGETED_DEVICE_FAMILY = "1,2"; 700 | }; 701 | name = Debug; 702 | }; 703 | FCF758F02084F651004CFF09 /* Release */ = { 704 | isa = XCBuildConfiguration; 705 | baseConfigurationReference = C7639950243EFB9A0710940A /* Pods-JFB.release.xcconfig */; 706 | buildSettings = { 707 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 708 | CODE_SIGN_STYLE = Automatic; 709 | INFOPLIST_FILE = JFB/Info.plist; 710 | LD_RUNPATH_SEARCH_PATHS = ( 711 | "$(inherited)", 712 | "@executable_path/Frameworks", 713 | ); 714 | PRODUCT_BUNDLE_IDENTIFIER = br.com.jera.JFB; 715 | PRODUCT_NAME = "$(TARGET_NAME)"; 716 | SWIFT_VERSION = 4.0; 717 | TARGETED_DEVICE_FAMILY = "1,2"; 718 | }; 719 | name = Release; 720 | }; 721 | FCF758F22084F651004CFF09 /* Debug */ = { 722 | isa = XCBuildConfiguration; 723 | baseConfigurationReference = 940F62BA8C01ECCE2574DC0D /* Pods-JFBTests.debug.xcconfig */; 724 | buildSettings = { 725 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 726 | BUNDLE_LOADER = "$(TEST_HOST)"; 727 | CODE_SIGN_STYLE = Automatic; 728 | INFOPLIST_FILE = JFBTests/Info.plist; 729 | LD_RUNPATH_SEARCH_PATHS = ( 730 | "$(inherited)", 731 | "@executable_path/Frameworks", 732 | "@loader_path/Frameworks", 733 | ); 734 | PRODUCT_BUNDLE_IDENTIFIER = br.com.jera.JFBTests; 735 | PRODUCT_NAME = "$(TARGET_NAME)"; 736 | SWIFT_VERSION = 4.0; 737 | TARGETED_DEVICE_FAMILY = "1,2"; 738 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JFB.app/JFB"; 739 | }; 740 | name = Debug; 741 | }; 742 | FCF758F32084F651004CFF09 /* Release */ = { 743 | isa = XCBuildConfiguration; 744 | baseConfigurationReference = B8C1CFF3BB059E919B8DA2F0 /* Pods-JFBTests.release.xcconfig */; 745 | buildSettings = { 746 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 747 | BUNDLE_LOADER = "$(TEST_HOST)"; 748 | CODE_SIGN_STYLE = Automatic; 749 | INFOPLIST_FILE = JFBTests/Info.plist; 750 | LD_RUNPATH_SEARCH_PATHS = ( 751 | "$(inherited)", 752 | "@executable_path/Frameworks", 753 | "@loader_path/Frameworks", 754 | ); 755 | PRODUCT_BUNDLE_IDENTIFIER = br.com.jera.JFBTests; 756 | PRODUCT_NAME = "$(TARGET_NAME)"; 757 | SWIFT_VERSION = 4.0; 758 | TARGETED_DEVICE_FAMILY = "1,2"; 759 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JFB.app/JFB"; 760 | }; 761 | name = Release; 762 | }; 763 | /* End XCBuildConfiguration section */ 764 | 765 | /* Begin XCConfigurationList section */ 766 | FCF758CC2084F650004CFF09 /* Build configuration list for PBXProject "JFB" */ = { 767 | isa = XCConfigurationList; 768 | buildConfigurations = ( 769 | FCF758EC2084F651004CFF09 /* Debug */, 770 | FCF758ED2084F651004CFF09 /* Release */, 771 | ); 772 | defaultConfigurationIsVisible = 0; 773 | defaultConfigurationName = Release; 774 | }; 775 | FCF758EE2084F651004CFF09 /* Build configuration list for PBXNativeTarget "JFB" */ = { 776 | isa = XCConfigurationList; 777 | buildConfigurations = ( 778 | FCF758EF2084F651004CFF09 /* Debug */, 779 | FCF758F02084F651004CFF09 /* Release */, 780 | ); 781 | defaultConfigurationIsVisible = 0; 782 | defaultConfigurationName = Release; 783 | }; 784 | FCF758F12084F651004CFF09 /* Build configuration list for PBXNativeTarget "JFBTests" */ = { 785 | isa = XCConfigurationList; 786 | buildConfigurations = ( 787 | FCF758F22084F651004CFF09 /* Debug */, 788 | FCF758F32084F651004CFF09 /* Release */, 789 | ); 790 | defaultConfigurationIsVisible = 0; 791 | defaultConfigurationName = Release; 792 | }; 793 | /* End XCConfigurationList section */ 794 | }; 795 | rootObject = FCF758C92084F650004CFF09 /* Project object */; 796 | } 797 | -------------------------------------------------------------------------------- /JFB.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JFB.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /JFB.xcodeproj/xcuserdata/vitormesquita.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | JFB.xcscheme 8 | 9 | orderHint 10 | 8 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /JFB/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | return true 19 | } 20 | 21 | func applicationWillResignActive(_ application: UIApplication) { 22 | // 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. 23 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 24 | } 25 | 26 | func applicationDidEnterBackground(_ application: UIApplication) { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | func applicationWillEnterForeground(_ application: UIApplication) { 32 | // 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. 33 | } 34 | 35 | func applicationDidBecomeActive(_ application: UIApplication) { 36 | // 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. 37 | } 38 | 39 | func applicationWillTerminate(_ application: UIApplication) { 40 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /JFB/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 | } -------------------------------------------------------------------------------- /JFB/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /JFB/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 | -------------------------------------------------------------------------------- /JFB/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 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /JFB/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 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /JFB/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Material 11 | 12 | class ViewController: UIViewController { 13 | 14 | let loginForm: [JField] = [ 15 | JTextField(id: "email", type: .email, placeholder: "E-mail", validations: [.required, .email]), 16 | JTextField(id: "password", type: .password, placeholder: "Password", validations: [.required, .minLength(6)]) 17 | // JTextField(id: "name", type: .name, placeholder: "Nome", validations: [.required]), 18 | // JTextField(id: "cpf", type: .cpf, placeholder: "CPF", validations: [.required, .cpf]), 19 | // JTextField(id: "phone", type: .phone, placeholder: "Telefone", validations: [.required]), 20 | // JDateField(id: "date", placeholder: "Data", validations: [.required]), 21 | // JTimeField(id: "time", placeholder: "Hora", validations: [.required]) 22 | ] 23 | 24 | lazy var vc: FormBuilderViewController = { FormBuilderViewController(fields: loginForm, delegate: self) }() 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | 29 | vc.submitTextColor = .white 30 | vc.submitBackgroundColor = Color.blue.base 31 | vc.submitText = "LOGIN" 32 | } 33 | 34 | @IBAction func action(_ sender: Any) { 35 | let nv = UINavigationController(rootViewController: vc) 36 | present(nv, animated: true) 37 | } 38 | } 39 | 40 | extension ViewController: FormBuilderDelegate { 41 | 42 | func formReceivedValues(_ values: [String: Any]) { 43 | print(values) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /JFBTests/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 | -------------------------------------------------------------------------------- /JFBTests/JFBTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JFBTests.swift 3 | // JFBTests 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import JFB 11 | 12 | class JFBTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Vitor mesquita 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. -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | platform :ios, '9.0' 3 | 4 | target 'JFB' do 5 | use_frameworks! 6 | inhibit_all_warnings! 7 | 8 | pod 'Eureka' 9 | pod 'SwiftLint' 10 | pod 'Material', '~> 2' 11 | pod 'NSStringMask', '~> 1.2' 12 | 13 | swift4 = ['Eureka', 'SwiftLint', 'Material'] 14 | 15 | post_install do |installer| 16 | installer.pods_project.targets.each do |target| 17 | swift_version = nil 18 | 19 | if swift4.include?(target.name) 20 | swift_version = '4.0' 21 | else 22 | swift_version = '3.2' 23 | end 24 | 25 | if swift_version 26 | target.build_configurations.each do |config| 27 | config.build_settings['SWIFT_VERSION'] = swift_version 28 | config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = '' 29 | end 30 | end 31 | end 32 | end 33 | 34 | end 35 | 36 | target 'JFBTests' do 37 | inherit! :search_paths 38 | end 39 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Eureka (4.1.1) 3 | - Material (2.14.0): 4 | - Material/Core (= 2.14.0) 5 | - Material/Core (2.14.0): 6 | - Motion (~> 1.3.0) 7 | - Motion (1.3.5): 8 | - Motion/Core (= 1.3.5) 9 | - Motion/Core (1.3.5) 10 | - NSStringMask (1.2.2) 11 | - SwiftLint (0.25.1) 12 | 13 | DEPENDENCIES: 14 | - Eureka 15 | - Material (~> 2) 16 | - NSStringMask (~> 1.2) 17 | - SwiftLint 18 | 19 | SPEC CHECKSUMS: 20 | Eureka: b88fb930e42c79f8c03c373d0fcdc28c1d6c50ed 21 | Material: c5bea030f57d4b903c5284200bb612d571c9ec03 22 | Motion: 9f74d115d7f72bb5380a8e3cde2f8a1fc898ac36 23 | NSStringMask: c0969955b28c4286418197696469665d9dcba313 24 | SwiftLint: ce933681be10c3266e82576dad676fa815a602e9 25 | 26 | PODFILE CHECKSUM: 24bb7a2339d3d221e4a2f0d38a651308e0ce3231 27 | 28 | COCOAPODS: 1.4.0 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # J.F.B (Jera Form Builder) 4 | 5 | *JFB* is Jera's way to create forms quickly and easily. 6 | 7 | We are using [**Eureka's**](https://github.com/xmartlabs/Eureka) enginee and [**Material**](https://github.com/CosmicMind/Material) components to concept good and beautiful forms. 8 | 9 | ## Requirements 10 | 11 | - Xcode 9.0+ 12 | - Swift 4.0+ 13 | 14 | ## Installation 15 | 16 | ### Pod 17 | 18 | JFB is available through [CocoaPods](http://cocoapods.org). To install following line at Podfile 19 | 20 | ```ruby 21 | pod 'JFB' 22 | ``` 23 | 24 | ### Carthage 25 | 26 | *Coming soon* 27 | 28 | ### Manually 29 | 30 | If you don't use any dependency managers, you can use JFB in your project manually just adding the files which contains [JFB Classes](https://github.com/vitormesquita/JFB/tree/master/Source) 31 | 32 | You will need to add JFB's dependecies libraries as well: 33 | 34 | - [Eureka](https://github.com/xmartlabs/Eureka) 35 | - [Material](https://github.com/CosmicMind/Material) 36 | 37 | ## Concept 38 | 39 | JFB helps you create forms with Material components (other layouts soon), and all concepts of a form like validations, masks ... 40 | 41 | 42 | 43 | Basically with a few code's line you can create a form just manipulating the result (to send to API for example) 44 | 45 | ### FormBuilderViewController 46 | 47 | **FormBuilderViewController** is the `UIViewController` that build all fields and create a submit button by default. 48 | 49 | To create it you will need pass an Array of **JField** and it's **FormBuilderDelegate** must by be implemented to receive form values as a Dictionary. 50 | 51 | #### JField 52 | 53 | It's a protocol that all fields will implement. 54 | 55 | **Fields List** 56 | 57 | - **JTextField** 58 | - **JDateField** 59 | - **JTimeField** 60 | - (Coming soon others) 61 | 62 | By default *JField* needs these attributes: 63 | 64 | - **id**: It's the dictionary Key that you'll receive value from form. 65 | - **placeholder**: It's the field's placeholder 66 | - **validations**: Set field's validation. 67 | 68 | ## Usage 69 | 70 | ### How to create a form 71 | 72 | Set your field an Array and call `FormBuilderViewController` passing your fields and delegate 73 | 74 | ```swift 75 | import JFB 76 | 77 | class ViewController: UIViewController { 78 | 79 | let loginFormFields: [JField] = [ 80 | JTextField(id: "email", type: .email, placeholder: "E-mail", validations: [.required, .email]), 81 | JTextField(id: "password", type: .password, placeholder: "Password", validations: [.required, 82 | .minLength(6)]) 83 | ] 84 | 85 | lazy var formViewController: FormBuilderViewController = { 86 | return FormBuilderViewController(fields: loginFormFields, delegate: self) 87 | }() 88 | 89 | override func viewDidLoad() { 90 | super.viewDidLoad() 91 | 92 | formViewController.submitText = .white 93 | formViewController.submitBackgroundColor = .blue 94 | formViewController.submitText = "LOGIN" 95 | } 96 | 97 | @IBAction func action(_ sender: Any) { 98 | let nv = UINavigationController(rootViewController: formViewController) 99 | present(nv, animated: true) 100 | } 101 | } 102 | 103 | extension ViewController: FormBuilderDelegate { 104 | 105 | func formReceivedValues(_ values: [String: Any]) { 106 | print(values) 107 | } 108 | } 109 | ``` 110 | ![Photo](https://github.com/vitormesquita/JFB/blob/develop/Assets/example_1.gif) 111 | 112 | ## Customize 113 | 114 | Of course form's layout always needs to be configured. So for this we provide some attributes to configure form layout as you want. 115 | 116 | ```swift 117 | /// Color to apply at all input tint color and navigation accessory view 118 | open var tintColor: UIColor = Color.blue.base 119 | 120 | /// Text to show on submit button 121 | open var submitText: String? 122 | 123 | /// Submit button's text color 124 | open var submitTextColor: UIColor 125 | 126 | /// Submit button's background color 127 | open var submitBackgroundColor: UIColor 128 | 129 | /// Submit button's background color when was disable 130 | open var submitDisableColor: UIColor 131 | 132 | /// Submit button's click callback color 133 | open var submitPulseColor: UIColor 134 | ``` 135 | 136 | If you want more customization please let we now, submit an issue explaning what kind of customization you need. 137 | 138 | ## Validations 139 | 140 | Each field has its own validations, so when you'll create a field need to pass an Array of `ValidationType`. 141 | 142 | **ValidationType List** 143 | 144 | - cpf 145 | - email 146 | - required 147 | - regex 148 | - maxLength 149 | - minLength 150 | 151 | The validation is applied on real time (when user is typping) and error message is showing as well. 152 | 153 | ## Author 154 | 155 | Vitor Mesquita, vitor.mesquita09@gmail.com 156 | 157 | ## License 158 | 159 | JFB is available under the MIT license. See the LICENSE file for more info. -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialBaseRow/MaterialBaseField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialBaseField.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | import Material 12 | 13 | class MaterialBaseField: Cell, CellType, UITextFieldDelegate where T: Equatable { 14 | 15 | override var detailTextLabel: UILabel? { 16 | return nil 17 | } 18 | 19 | internal lazy var field: TextField = { 20 | let textField = TextField() 21 | textField.translatesAutoresizingMaskIntoConstraints = false 22 | return textField 23 | }() 24 | 25 | override func setup() { 26 | super.setup() 27 | addTextField() 28 | 29 | selectionStyle = .none 30 | height = { return 74 } 31 | 32 | field.delegate = self 33 | } 34 | 35 | open override func cellCanBecomeFirstResponder() -> Bool { 36 | return !row.isDisabled && field.canBecomeFirstResponder == true 37 | } 38 | 39 | open override func cellBecomeFirstResponder(withDirection: Direction) -> Bool { 40 | return field.becomeFirstResponder() 41 | } 42 | 43 | open override func cellResignFirstResponder() -> Bool { 44 | return field.resignFirstResponder() 45 | } 46 | 47 | // MARK: - UITextFieldDelegate 48 | 49 | func textFieldDidBeginEditing(_ textField: UITextField) { 50 | formViewController()?.beginEditing(of: self) 51 | formViewController()?.textInputDidBeginEditing(textField, cell: self) 52 | } 53 | 54 | func textFieldDidEndEditing(_ textField: UITextField) { 55 | formViewController()?.endEditing(of: self) 56 | formViewController()?.textInputDidEndEditing(textField, cell: self) 57 | } 58 | 59 | func textFieldShouldReturn(_ textField: UITextField) -> Bool { 60 | return formViewController()?.textInputShouldReturn(textField, cell: self) ?? true 61 | } 62 | 63 | func textFieldShouldClear(_ textField: UITextField) -> Bool { 64 | return formViewController()?.textInputShouldClear(textField, cell: self) ?? true 65 | } 66 | 67 | func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 68 | return formViewController()?.textInput(textField, shouldChangeCharactersInRange: range, replacementString: string, cell: self) ?? true 69 | } 70 | } 71 | 72 | extension MaterialBaseField { 73 | 74 | func addTextField() { 75 | field.removeFromSuperview() 76 | 77 | contentView.addSubview(field) 78 | 79 | let constraints = [ 80 | field.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16), 81 | field.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), 82 | field.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16), 83 | field.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16) 84 | ] 85 | 86 | NSLayoutConstraint.activate(constraints) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialBaseRow/MaterialBaseRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialBaseRow.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | class MaterialBaseRow: Row where Cell: BaseCell { 13 | 14 | var placeholder: String? 15 | 16 | var tintColor: UIColor? { 17 | didSet { cell.update() } 18 | } 19 | 20 | var formattedText: String? { 21 | return nil 22 | } 23 | 24 | required init(tag: String?) { 25 | super.init(tag: tag) 26 | } 27 | 28 | func clearText() { 29 | value = nil 30 | cell.update() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialDate/MaterialDateCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialDateCell.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 18/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | final class MaterialDateCell: MaterialBaseField { 12 | 13 | private var materialRow: MaterialBaseDateRow { 14 | return row as! MaterialBaseDateRow 15 | } 16 | 17 | private var datePicker = UIDatePicker() 18 | 19 | override func setup() { 20 | super.setup() 21 | 22 | datePicker.minuteInterval = materialRow.minuteInterval ?? datePicker.minuteInterval 23 | datePicker.addTarget(self, action: #selector(datePickerValueChanged(_:)), for: .valueChanged) 24 | 25 | field.configureWithType(.text) 26 | field.inputView = datePicker 27 | 28 | if let dateRow = materialRow as? MaterialDateRow { 29 | datePicker.datePickerMode = .date 30 | datePicker.minimumDate = dateRow.minDate 31 | datePicker.maximumDate = dateRow.maxDate 32 | } 33 | 34 | if materialRow is MaterialTimeRow { 35 | datePicker.datePickerMode = .time 36 | datePicker.minimumDate = nil 37 | datePicker.maximumDate = nil 38 | } 39 | } 40 | 41 | override func update() { 42 | super.update() 43 | 44 | field.text = materialRow.formattedText 45 | field.placeholder = materialRow.placeholder 46 | field.detail = materialRow.validationErrors.first?.msg 47 | field.dividerActiveColor = materialRow.tintColor ?? field.dividerActiveColor 48 | field.placeholderActiveColor = materialRow.tintColor ?? field.placeholderActiveColor 49 | } 50 | 51 | @objc private func datePickerValueChanged(_ sender: UIDatePicker) { 52 | materialRow.didSelectDate(sender.date) 53 | } 54 | 55 | override func textFieldShouldClear(_ textField: UITextField) -> Bool { 56 | materialRow.clearText() 57 | return false 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialDate/MaterialDateRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialDateRow.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 18/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | class MaterialBaseDateRow: MaterialBaseRow { 13 | 14 | var minuteInterval: Int? 15 | var dateFormatter = DateFormatter() 16 | 17 | func didSelectDate(_ date: Date) { /* Do nothing */} 18 | } 19 | 20 | final class MaterialDateRow: MaterialBaseDateRow, RowType { 21 | 22 | open var minDate: Date? 23 | open var maxDate: Date? 24 | 25 | open var displayFormat: String = "dd/MM/yyyy" 26 | 27 | override var formattedText: String? { 28 | dateFormatter.dateFormat = "yyyy-MM-dd" 29 | guard let date = dateFormatter.date(from: value ?? "") else { return nil } 30 | dateFormatter.dateFormat = displayFormat 31 | return dateFormatter.string(from: date) 32 | } 33 | 34 | required init(tag: String?) { 35 | super.init(tag: tag) 36 | cellProvider = CellProvider() 37 | } 38 | 39 | override func didSelectDate(_ date: Date) { 40 | dateFormatter.dateFormat = "yyyy-MM-dd" 41 | value = dateFormatter.string(from: date) 42 | cell.update() 43 | } 44 | } 45 | 46 | final class MaterialTimeRow: MaterialBaseDateRow, RowType { 47 | 48 | override var formattedText: String? { 49 | return value 50 | } 51 | 52 | required init(tag: String?) { 53 | super.init(tag: tag) 54 | cellProvider = CellProvider() 55 | } 56 | 57 | override func didSelectDate(_ date: Date) { 58 | dateFormatter.dateFormat = "HH:mm" 59 | value = dateFormatter.string(from: date) 60 | cell.update() 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialSubmit/MaterialSubmitCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialSubmitCell.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Material 11 | import Eureka 12 | 13 | final class MaterialSubmitCell: Cell, CellType { 14 | 15 | @IBOutlet weak var submitButton: RaisedButton! 16 | 17 | private var materialRow: MaterialSubmitRow { 18 | return row as! MaterialSubmitRow 19 | } 20 | 21 | override func awakeFromNib() { 22 | super.awakeFromNib() 23 | submitButton.addTarget(self, action: #selector(self.didTapSubmition), for: .touchUpInside) 24 | } 25 | 26 | override func setup() { 27 | super.setup() 28 | selectionStyle = .none 29 | accessoryView = .none 30 | 31 | height = { return 82} 32 | } 33 | 34 | override func update() { 35 | super.update() 36 | 37 | submitButton.pulseColor = materialRow.pulseColor 38 | submitButton.backgroundColor = materialRow.backgroundColor 39 | submitButton.setTitle(materialRow.submitTitle, for: .normal) 40 | submitButton.setTitleColor(materialRow.textColor, for: .normal) 41 | submitButton.setBackgroundImage(UIImage.fromColor(color: materialRow.disableColor), for: .disabled) 42 | 43 | submitButton.isEnabled = formViewController()?.form.validate().isEmpty ?? false 44 | } 45 | 46 | @objc private func didTapSubmition() { 47 | formViewController()?.view.endEditing(true) 48 | materialRow.submitBlock?() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialSubmit/MaterialSubmitCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialSubmit/MaterialSubmitRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialSubmitRow.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | final class MaterialSubmitRow: Row, RowType { 13 | 14 | open var submitTitle: String? 15 | 16 | open var textColor: UIColor = .black 17 | open var backgroundColor: UIColor = .white 18 | open var disableColor: UIColor = .lightGray 19 | open var pulseColor: UIColor = .lightGray 20 | 21 | var submitBlock: (() -> Void)? 22 | 23 | required init(tag: String?) { 24 | super.init(tag: tag) 25 | cellProvider = CellProvider(nibName: "MaterialSubmitCell") 26 | } 27 | 28 | public func didSubmit(_ callback: @escaping () -> Void) -> MaterialSubmitRow { 29 | self.submitBlock = callback 30 | return self 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialText/MaterialTextFieldCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialTextFieldCell.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | final class MaterialTextFieldCell: MaterialBaseField { 13 | 14 | private var materialRow: MaterialTextRow { 15 | return row as! MaterialTextRow 16 | } 17 | 18 | override func setup() { 19 | super.setup() 20 | field.configureWithType(materialRow.fieldType) 21 | field.addTarget(self, action: #selector(textDidChange(_:)), for: .editingChanged) 22 | } 23 | 24 | override func update() { 25 | super.update() 26 | 27 | field.placeholder = materialRow.placeholder 28 | field.detail = materialRow.validationErrors.first?.msg 29 | field.dividerActiveColor = materialRow.tintColor ?? field.dividerActiveColor 30 | field.placeholderActiveColor = materialRow.tintColor ?? field.placeholderActiveColor 31 | 32 | if materialRow.fieldType.hasMask { 33 | field.text = materialRow.formattedText 34 | } 35 | } 36 | 37 | @objc private func textDidChange(_ textField: UITextField) { 38 | guard !materialRow.fieldType.hasMask else { return } 39 | materialRow.setValue(text: textField.text) 40 | } 41 | 42 | // MARK: - UITextFieldDelegate 43 | 44 | override func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 45 | if materialRow.fieldType.hasMask { 46 | materialRow.updateText(text: string, range: range) 47 | return false 48 | } 49 | 50 | return super.textField(textField, shouldChangeCharactersIn: range, replacementString: string) 51 | } 52 | 53 | override func textFieldShouldClear(_ textField: UITextField) -> Bool { 54 | materialRow.clearText() 55 | 56 | if materialRow.fieldType.hasMask { 57 | return false 58 | } 59 | 60 | return super.textFieldShouldClear(textField) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Source/Cells/Material/MaterialText/MaterialTextRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialTextRow.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | final class MaterialTextRow: MaterialBaseRow, RowType { 13 | 14 | var fieldType: TextFieldType = .text 15 | 16 | required init(tag: String?) { 17 | super.init(tag: tag) 18 | cellProvider = CellProvider() 19 | } 20 | 21 | /// Formatted text just for fields that have any kind of mask 22 | override var formattedText: String? { 23 | return fieldType.applyMask(value) 24 | } 25 | 26 | /// To update value if doesn't have mask 27 | func setValue(text: String?) { 28 | if let text = text, !text.isEmpty { 29 | value = text 30 | } else { 31 | value = nil 32 | } 33 | } 34 | 35 | /// To update text if has mask 36 | func updateText(text: String, range: NSRange) { 37 | if range.length == value?.count { 38 | clearText() 39 | return 40 | } 41 | 42 | var allText = value ?? "" 43 | 44 | if !text.isEmpty { 45 | allText += text 46 | } 47 | 48 | if text.isEmpty && !allText.isEmpty { 49 | allText.removeLast() 50 | 51 | let removedLastText = allText 52 | allText = "" 53 | 54 | for character in removedLastText { 55 | allText += String(character) 56 | } 57 | } 58 | 59 | if allText.count <= fieldType.max { 60 | value = allText.isEmpty ? nil : allText 61 | cell.update() 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/Fields/JDateField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JDateField.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | public struct JDateField: JField { 13 | 14 | public var id: String 15 | public var placeholder: String? 16 | public var validations: [ValidationType] 17 | 18 | var displayFormat: String 19 | var minDate: Date? 20 | var maxDate: Date? 21 | 22 | private var ruleSet: RuleSet { 23 | return buildValidations(validations: validations) 24 | } 25 | 26 | init(id: String, 27 | placeholder: String? = nil, 28 | validations: [ValidationType] = [], 29 | minDate: Date? = nil, 30 | maxDate: Date? = nil, 31 | displayFormat: String = "dd/MM/yyyy") { 32 | 33 | self.id = id 34 | self.placeholder = placeholder 35 | self.validations = validations 36 | self.minDate = minDate 37 | self.maxDate = maxDate 38 | self.displayFormat = displayFormat 39 | } 40 | 41 | public func build() -> BaseRow { 42 | return MaterialDateRow(id) { row in 43 | row.placeholder = placeholder 44 | row.minDate = minDate 45 | row.maxDate = maxDate 46 | row.displayFormat = displayFormat 47 | row.add(ruleSet: ruleSet) 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Source/Fields/JField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JField.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | public protocol JField { 12 | 13 | var id: String { get set } 14 | var placeholder: String? { get set } 15 | var validations: [ValidationType] { get set } 16 | 17 | func build() -> BaseRow 18 | } 19 | 20 | func buildValidations(validations: [ValidationType]) -> RuleSet { 21 | var rules = RuleSet() 22 | validations.forEach { (type) in 23 | switch type { 24 | case .required: 25 | rules.add(rule: RuleRequired(msg: "")) 26 | 27 | case .email: 28 | rules.add(rule: RuleEmail()) 29 | 30 | case .maxLength(let length): 31 | rules.add(rule: RuleMaxLength(maxLength: UInt(length))) 32 | 33 | case .minLength(let length): 34 | rules.add(rule: RuleMinLength(minLength: UInt(length))) 35 | 36 | case .cpf: 37 | rules.add(rule: RuleCPF()) 38 | 39 | case .regex(let regex): 40 | rules.add(rule: RuleRegExp(regExpr: regex)) 41 | } 42 | } 43 | return rules 44 | } 45 | -------------------------------------------------------------------------------- /Source/Fields/JTextField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JTextField.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | public struct JTextField: JField { 12 | 13 | public var id: String 14 | public var placeholder: String? 15 | public var validations: [ValidationType] 16 | 17 | let type: TextFieldType 18 | 19 | private var ruleSet: RuleSet { 20 | return buildValidations(validations: validations) 21 | } 22 | 23 | public init(id: String, type: TextFieldType, placeholder: String? = nil, validations: [ValidationType] = []) { 24 | self.id = id 25 | self.type = type 26 | self.placeholder = placeholder 27 | self.validations = validations 28 | } 29 | 30 | public func build() -> BaseRow { 31 | return MaterialTextRow(id) { (row) in 32 | row.fieldType = type 33 | row.placeholder = placeholder 34 | row.add(ruleSet: ruleSet) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Fields/JTimeField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JTimeField.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 18/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Eureka 11 | 12 | public struct JTimeField: JField { 13 | 14 | public var id: String 15 | public var placeholder: String? 16 | public var validations: [ValidationType] 17 | 18 | var minInterval: Int? 19 | 20 | private var ruleSet: RuleSet { 21 | return buildValidations(validations: validations) 22 | } 23 | 24 | init(id: String, placeholder: String? = nil, validations: [ValidationType] = [], minInterval: Int? = nil) { 25 | self.id = id 26 | self.placeholder = placeholder 27 | self.validations = validations 28 | self.minInterval = minInterval 29 | } 30 | 31 | public func build() -> BaseRow { 32 | return MaterialTimeRow(id) { row in 33 | row.placeholder = placeholder 34 | row.minuteInterval = minInterval 35 | row.add(ruleSet: ruleSet) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/FormBuilderDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormBuilderDelegate.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol FormBuilderDelegate: class { 12 | 13 | func formReceivedValues(_ values: [String: Any]) 14 | } 15 | -------------------------------------------------------------------------------- /Source/FormBuilderViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormBuilderViewController.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | import Material 11 | 12 | public class FormBuilderViewController: FormViewController { 13 | 14 | // MARK: - Public 15 | 16 | /// Color to apply at all input tint color and navigation accessory view 17 | open var tintColor: UIColor = Color.blue.base 18 | 19 | /// Text to show on submit button 20 | open var submitText: String? { 21 | set { submitRow.submitTitle = newValue } 22 | get { return submitRow.submitTitle } 23 | } 24 | 25 | /// Submit button's text color 26 | open var submitTextColor: UIColor { 27 | set { submitRow.textColor = newValue } 28 | get { return submitRow.textColor } 29 | } 30 | 31 | /// Submit button's background color 32 | open var submitBackgroundColor: UIColor { 33 | set { submitRow.backgroundColor = newValue } 34 | get { return submitRow.backgroundColor } 35 | } 36 | 37 | /// Submit button's background color when was disable 38 | open var submitDisableColor: UIColor { 39 | set { submitRow.disableColor = newValue } 40 | get { return submitRow.disableColor } 41 | } 42 | 43 | /// Submit button's click callback color 44 | open var submitPulseColor: UIColor { 45 | set { submitRow.pulseColor = newValue } 46 | get { return submitRow.pulseColor } 47 | } 48 | 49 | // MARK: - Private 50 | 51 | private var fields: [JField] = [] 52 | private weak var delegate: FormBuilderDelegate? 53 | 54 | private lazy var mainSection: Section = { 55 | return Section() 56 | }() 57 | 58 | private lazy var submitRow: MaterialSubmitRow = { 59 | return MaterialSubmitRow().didSubmit {[weak self] in 60 | guard let strongSelf = self else { return } 61 | strongSelf.filterValuesToSubmit() 62 | } 63 | }() 64 | 65 | // MARK: - Inits 66 | 67 | public init(fields: [JField], delegate: FormBuilderDelegate?) { 68 | super.init(style: .plain) 69 | 70 | self.fields = fields 71 | self.delegate = delegate 72 | 73 | fields.map { $0.build() }.forEach {[unowned self] (row) in 74 | self.mainSection <<< row 75 | } 76 | } 77 | 78 | required public init?(coder aDecoder: NSCoder) { 79 | super.init(coder: aDecoder) 80 | } 81 | 82 | // MARK: - Lifecycle 83 | 84 | override public func viewDidLoad() { 85 | super.viewDidLoad() 86 | 87 | tableView.separatorStyle = .none 88 | 89 | form +++ mainSection 90 | form +++ submitRow 91 | 92 | setOnChangeValueToUpdateSubmitButton() 93 | applyLayoutForRows() 94 | } 95 | 96 | // MARK: - Utils 97 | 98 | /// TODO refactor 99 | private func setOnChangeValueToUpdateSubmitButton() { 100 | form.allRows.forEach { (row) in 101 | 102 | if let materialTextRow = row as? MaterialTextRow { 103 | materialTextRow.onChange { (row) in self.submitRow.updateCell() } 104 | } 105 | 106 | if let materialDateRow = row as? MaterialDateRow { 107 | materialDateRow.onChange { (row) in self.submitRow.updateCell() } 108 | } 109 | 110 | if let materialDateRow = row as? MaterialTimeRow { 111 | materialDateRow.onChange { (row) in self.submitRow.updateCell() } 112 | } 113 | } 114 | } 115 | 116 | /// TODO refactor 117 | private func applyLayoutForRows() { 118 | navigationAccessoryView.tintColor = tintColor 119 | 120 | form.allRows.forEach { (row) in 121 | 122 | if let materialTextRow = row as? MaterialTextRow { 123 | materialTextRow.tintColor = tintColor 124 | } 125 | 126 | if let materialDateRow = row as? MaterialDateRow { 127 | materialDateRow.tintColor = tintColor 128 | } 129 | } 130 | } 131 | 132 | /// 133 | private func filterValuesToSubmit() { 134 | let values = form.values() 135 | .filter { $0.value != nil } 136 | .mapValues { $0! } 137 | 138 | delegate?.formReceivedValues(values) 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /Source/Rules/RuleCPF.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RuleCPF.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Eureka 11 | 12 | public struct RuleCPF: RuleType { 13 | 14 | public typealias RowValueType = String 15 | 16 | public var id: String? 17 | public var validationError: ValidationError 18 | 19 | init(msg: String = "CPF inválido") { 20 | self.validationError = ValidationError(msg: msg) 21 | } 22 | 23 | public func isValid(value: String?) -> ValidationError? { 24 | guard let value = value, !value.isEmpty else { return ValidationError(msg: "") } 25 | return value.count == 11 ? nil : validationError 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Source/Sections/JSection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // JSection.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | protocol JSection { 12 | func build() -> Section 13 | } 14 | -------------------------------------------------------------------------------- /Source/Utils/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - UIImage 12 | extension UIImage { 13 | 14 | static func fromColor(color: UIColor) -> UIImage { 15 | let rect = CGRect(x: 0, y: 0, width: 1, height: 1) 16 | UIGraphicsBeginImageContext(rect.size) 17 | let context = UIGraphicsGetCurrentContext()! 18 | context.setFillColor(color.cgColor) 19 | context.fill(rect) 20 | 21 | let img = UIGraphicsGetImageFromCurrentImageContext()! 22 | UIGraphicsEndImageContext() 23 | return img 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/Utils/FormEnums.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormRowType.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 16/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import NSStringMask 11 | 12 | public enum LayoutType { 13 | case material 14 | case cupertino 15 | } 16 | 17 | public enum ValidationType { 18 | case cpf 19 | case email 20 | case required 21 | case regex(String) 22 | case maxLength(Int) 23 | case minLength(Int) 24 | } 25 | 26 | public enum TextFieldType { 27 | case email 28 | case password 29 | case text 30 | case name 31 | case phone 32 | case cpf 33 | 34 | var max: Int { 35 | switch self { 36 | case .cpf, 37 | .phone: 38 | return 11 39 | default: 40 | return Int.max 41 | } 42 | } 43 | 44 | var hasMask: Bool { 45 | switch self { 46 | case .cpf, 47 | .phone: 48 | return true 49 | default: 50 | return false 51 | } 52 | } 53 | 54 | func applyMask(_ string: String?) -> String? { 55 | switch self { 56 | case .phone: 57 | return NSStringMask.maskString(string, withPattern: "\\((\\d{2})\\) (\\d{5})-(\\d{4})") 58 | case .cpf: 59 | return NSStringMask.maskString(string, withPattern: "(\\d{3}).(\\d{3}).(\\d{3})-(\\d{2})") 60 | default: 61 | return string 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Source/Utils/MaterialAppearence.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MaterialAppearence.swift 3 | // JFB 4 | // 5 | // Created by Vitor Mesquita on 17/04/2018. 6 | // Copyright © 2018 Jera. All rights reserved. 7 | // 8 | 9 | import Material 10 | 11 | extension TextField { 12 | 13 | func configureWithType(_ type: TextFieldType) { 14 | 15 | if #available(iOS 10.0, *) { 16 | self.textContentType = UITextContentType("") 17 | } 18 | 19 | self.detailColor = .red 20 | self.detailVerticalOffset = 0 21 | self.placeholderVerticalOffset = 35.0 22 | self.clearButtonMode = .whileEditing 23 | 24 | switch type { 25 | 26 | case .email: 27 | self.keyboardType = .emailAddress 28 | self.autocorrectionType = .no 29 | self.autocapitalizationType = .none 30 | 31 | case .cpf: 32 | self.keyboardType = .numberPad 33 | self.autocorrectionType = .no 34 | self.autocapitalizationType = .none 35 | 36 | case .phone: 37 | self.keyboardType = .phonePad 38 | self.autocorrectionType = .no 39 | self.autocapitalizationType = .none 40 | 41 | case .password: 42 | self.keyboardType = .default 43 | self.autocorrectionType = .no 44 | self.autocapitalizationType = .none 45 | self.isVisibilityIconButtonEnabled = true 46 | 47 | if #available(iOS 11.0, *) { 48 | self.textContentType = .password 49 | } 50 | 51 | case .name: 52 | self.keyboardType = .default 53 | self.autocorrectionType = .no 54 | self.autocapitalizationType = .words 55 | 56 | case .text: 57 | self.keyboardType = .default 58 | self.autocorrectionType = .no 59 | self.autocapitalizationType = .sentences 60 | } 61 | } 62 | } 63 | --------------------------------------------------------------------------------