├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── ci.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Documentation ├── Eureka 2.0 Migration Guide.md └── README_CN.md ├── Eureka.playground ├── Contents.swift ├── contents.xcplayground ├── playground.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── timeline.xctimeline ├── Eureka.png ├── Eureka.podspec ├── Eureka.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Eureka.xcscheme ├── Eureka.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Example.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ └── Example.xcscheme ├── Example ├── EmojiCell.xib ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── Contents.json │ │ │ ├── appIcon20pt@2x.png │ │ │ ├── appIcon20pt@3x.png │ │ │ ├── appIcon29pt@1x.png │ │ │ ├── appIcon29pt@2x.png │ │ │ ├── appIcon29pt@3x.png │ │ │ ├── appIcon40pt@2x.png │ │ │ ├── appIcon40pt@3x.png │ │ │ ├── appIcon60pt@2x.png │ │ │ ├── appIcon60pt@3x.png │ │ │ ├── appIcon76pt@1x.png │ │ │ ├── appIcon76pt@2x.png │ │ │ └── appIcon83-5pt@2x.png │ │ ├── Contents.json │ │ ├── Eureka.imageset │ │ │ ├── Contents.json │ │ │ └── Eureka@2x.png │ │ ├── checkedDay.imageset │ │ │ ├── Contents.json │ │ │ └── checkedDay.png │ │ ├── map_pin.imageset │ │ │ ├── Contents.json │ │ │ ├── map_pin@2x.png │ │ │ └── map_pin@3x.png │ │ ├── plus_image.imageset │ │ │ ├── Contents.json │ │ │ ├── plus_image@2x.png │ │ │ └── plus_image@3x.png │ │ ├── selected.imageset │ │ │ ├── Contents.json │ │ │ ├── selectedCircle@2x.png │ │ │ └── selectedCircle@3x.png │ │ ├── selectedRectangle.imageset │ │ │ ├── Contents.json │ │ │ ├── selectedRectangle@2x.png │ │ │ └── selectedRectangle@3x.png │ │ ├── uncheckedDay.imageset │ │ │ ├── Contents.json │ │ │ └── uncheckedDay.png │ │ ├── unselected.imageset │ │ │ ├── Contents.json │ │ │ ├── unselectedCircle@2x.png │ │ │ └── unselectedCircle@3x.png │ │ └── unselectedRectangle.imageset │ │ │ ├── Contents.json │ │ │ ├── unselectedRectangle@2x.png │ │ │ └── unselectedRectangle@3x.png │ ├── Base.lproj │ │ ├── EurekaSectionHeader.xib │ │ ├── LaunchScreen.storyboard │ │ ├── Main.storyboard │ │ └── WeekDaysCell.xib │ ├── Controllers │ │ ├── CustomCellsViewController.swift │ │ ├── CustomDesignController.swift │ │ ├── DisabledRowsExample.swift │ │ ├── FieldRowCustomizationController.swift │ │ ├── FormatterExample.swift │ │ ├── HiddenRowsExample.swift │ │ ├── InlineRowsExample.swift │ │ ├── ListSectionsController.swift │ │ ├── MultivaluedExamples.swift │ │ ├── NativeEventExample.swift │ │ ├── NavigationAccessoryController.swift │ │ ├── PlainTableViewExample.swift │ │ ├── RowsExample.swift │ │ ├── SwipeActionsController.swift │ │ └── ValidationsController.swift │ ├── CustomCells.swift │ ├── CustomDesign │ │ ├── DatePickerCell.xib │ │ ├── SwitchCell.xib │ │ └── TextCell.xib │ ├── CustomRows │ │ └── ImageRow │ │ │ ├── ImagePickerController.swift │ │ │ └── ImageRow.swift │ ├── Helpers │ │ └── FloatLabelTextField.swift │ ├── Info.plist │ └── ViewController.swift ├── Media │ ├── CatalogFieldRows.jpg │ ├── EurekaAlertRow.gif │ ├── EurekaCustomCellDisabled.gif │ ├── EurekaCustomCells.gif │ ├── EurekaCustomRow.gif │ ├── EurekaExample1.gif │ ├── EurekaExample2.gif │ ├── EurekaExample3.gif │ ├── EurekaHidden.gif │ ├── EurekaHowTo.gif │ ├── EurekaLocationRow.gif │ ├── EurekaMultivalued.gif │ ├── EurekaNavigation.gif │ ├── EurekaOnChange.gif │ ├── EurekaRows.gif │ ├── EurekaSegmentedRow.gif │ ├── EurekaSwitchSections.gif │ ├── RowGifs │ │ ├── EurekaCountDownInlineRow.gif │ │ ├── EurekaCountDownPickerRow.gif │ │ ├── EurekaCountDownRow.gif │ │ ├── EurekaDateInlineRow.gif │ │ ├── EurekaDatePickerRow.gif │ │ ├── EurekaDateRow.gif │ │ ├── EurekaDateTimeInlineRow.gif │ │ ├── EurekaDateTimePickerRow.gif │ │ ├── EurekaDateTimeRow.gif │ │ ├── EurekaTimeInlineRow.gif │ │ ├── EurekaTimePickerRow.gif │ │ └── EurekaTimeRow.gif │ └── RowStatics │ │ ├── ActionSheetRow.jpeg │ │ ├── AlertRow.jpeg │ │ ├── ButtonRow.png │ │ ├── CheckRow.png │ │ ├── ImageRow.jpeg │ │ ├── LabelRow.png │ │ ├── MultipleSelectorRow.jpeg │ │ ├── PickerRow.png │ │ ├── PictureRow.png │ │ ├── PostalAddressRow.png │ │ ├── PushRow.jpeg │ │ ├── SegmentedRow.png │ │ ├── SegmentedRowWithTitle.png │ │ ├── SliderRow.png │ │ ├── StepperRow.png │ │ ├── SwitchRow.png │ │ └── TextAreaRow.png └── UITests │ ├── FieldRowUITests.swift │ └── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── Source ├── Assets.xcassets │ └── Contents.json ├── Core │ ├── BaseRow.swift │ ├── Cell.swift │ ├── CellType.swift │ ├── Core.swift │ ├── Form.swift │ ├── HeaderFooterView.swift │ ├── Helpers.swift │ ├── InlineRowType.swift │ ├── NavigationAccessoryView.swift │ ├── Operators.swift │ ├── PresenterRowType.swift │ ├── ResultBuilders.swift │ ├── Row.swift │ ├── RowControllerType.swift │ ├── RowProtocols.swift │ ├── RowType.swift │ ├── Section.swift │ ├── SelectableRowType.swift │ ├── SelectableSection.swift │ ├── SwipeActions.swift │ └── Validation.swift ├── Eureka.h ├── Info.plist ├── PrivacyInfo.xcprivacy ├── Rows │ ├── ActionSheetRow.swift │ ├── AlertRow.swift │ ├── ButtonRow.swift │ ├── ButtonRowWithPresent.swift │ ├── CheckRow.swift │ ├── Common │ │ ├── AlertOptionsRow.swift │ │ ├── DateFieldRow.swift │ │ ├── DateInlineFieldRow.swift │ │ ├── DecimalFormatter.swift │ │ ├── FieldRow.swift │ │ ├── GenericMultipleSelectorRow.swift │ │ ├── OptionsRow.swift │ │ ├── Protocols.swift │ │ └── SelectorRow.swift │ ├── Controllers │ │ ├── MultipleSelectorViewController.swift │ │ ├── SelectorAlertController.swift │ │ └── SelectorViewController.swift │ ├── DateInlineRow.swift │ ├── DatePickerRow.swift │ ├── DateRow.swift │ ├── DoublePickerInputRow.swift │ ├── DoublePickerRow.swift │ ├── FieldsRow.swift │ ├── LabelRow.swift │ ├── MultipleSelectorRow.swift │ ├── PickerInlineRow.swift │ ├── PickerInputRow.swift │ ├── PickerRow.swift │ ├── PopoverSelectorRow.swift │ ├── PushRow.swift │ ├── SegmentedRow.swift │ ├── SelectableRows │ │ └── ListCheckRow.swift │ ├── SliderRow.swift │ ├── StepperRow.swift │ ├── SwitchRow.swift │ ├── TextAreaRow.swift │ ├── TriplePickerInputRow.swift │ └── TriplePickerRow.swift └── Validations │ ├── RuleClosure.swift │ ├── RuleEmail.swift │ ├── RuleEqualsToRow.swift │ ├── RuleLength.swift │ ├── RuleRange.swift │ ├── RuleRegExp.swift │ ├── RuleRequired.swift │ └── RuleURL.swift ├── Tests ├── BaseEurekaTests.swift ├── CallbacksTests.swift ├── CollectionTests.swift ├── DateTests.swift ├── FormValuesTests.swift ├── HelperMethodTests.swift ├── HiddenRowsTests.swift ├── Info.plist ├── MultivaluedSectionTests.swift ├── OperatorsTest.swift ├── ResultBuildersTests.swift ├── RowByTagTests.swift ├── RowCallbackTests.swift ├── RowsInsertionTests.swift ├── SectionsInsertionTests.swift ├── SelectableSectionTests.swift ├── SetValuesTests.swift └── ValidationsTests.swift └── donate.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: xmartlabs # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Before submitting issues ... 2 | 3 | - Make sure you are using Eureka [latest release](https://github.com/xmartlabs/Eureka/releases) or master branch version. 4 | - Make sure your Xcode version is the latest stable one. 5 | - Check if the issue was [already reported or fixed](https://github.com/xmartlabs/Eureka/issues?utf8=%E2%9C%93&q=is%3Aissue). We add labels to each issue in order to easily find related issues. If you found a match add a brief comment "I have the same problem" or "+1". 6 | 7 | When submitting issues, please provide the following information to help maintainers to fix the problem faster: 8 | 9 | - Environment: Eureka, Xcode and iOS version you are using. 10 | - In case of reporting errors, provide Xcode console output of stack trace or code compilation error. 11 | - Any other additional detail such as your eureka form/section/row code that you think it would be useful to understand and solve the problem. 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve. Please make sure to search for existing 4 | issues or in the Readme before posting. 5 | title: '' 6 | labels: '' 7 | assignees: '' 8 | 9 | --- 10 | 11 | **Describe the bug** 12 | A clear and concise description of what the bug is. 13 | 14 | **To Reproduce** 15 | Steps to reproduce the behavior: 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Versions (please complete the following information):** 28 | - Device: [e.g. iPhone 13] 29 | - OS: [e.g. iOS 15.0] 30 | - Eureka Version [e.g. 5.3.5] 31 | - Xcode version [e.g. 13.1] 32 | 33 | **Additional context** 34 | Add any other context about the problem here. Console output, stack traces, etc. 35 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: 'type: feature request' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Before submitting...** 11 | Please check whether such a feature has already been requested. 12 | 13 | **Is your feature request related to a problem? Please describe.** 14 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 15 | 16 | **Describe the solution you'd like** 17 | A clear and concise description of what you want to happen. 18 | 19 | **Describe alternatives you've considered** 20 | A clear and concise description of any alternative solutions or features you've considered. 21 | 22 | **Additional context** 23 | Add any other context or screenshots about the feature request here. 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/.github/PULL_REQUEST_TEMPLATE.md -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Eureka CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | iOS: 11 | runs-on: macos-12 12 | strategy: 13 | matrix: 14 | destination: ['platform=iOS Simulator,OS=16.0,name=iPhone 14'] 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: maxim-lobanov/setup-xcode@v1 19 | with: 20 | xcode-version: '14.0.1' 21 | - name: Build and test 22 | run: set -o pipefail && xcodebuild -project Eureka.xcodeproj -scheme 'Eureka' -sdk 'iphonesimulator' -destination "${{ matrix.destination }}" -configuration Debug test | xcpretty 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | *.xcscmblueprint 20 | .LSOverride 21 | 22 | # CocoaPods 23 | # 24 | # We recommend against adding the Pods directory to your .gitignore. However 25 | # you should judge for yourself, the pros and cons are mentioned at: 26 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 27 | # 28 | # Pods/ 29 | 30 | # Carthage 31 | # 32 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 33 | # Carthage/Checkouts 34 | 35 | Carthage/Build 36 | -------------------------------------------------------------------------------- /Documentation/Eureka 2.0 Migration Guide.md: -------------------------------------------------------------------------------- 1 | # Eureka 2.0 Migration Guide 2 | 3 | #### Requirements: 4 | 5 | Eureka 2.0.0 needs Xcode 8, Swift3+ to work. Minimum supported iOS version is 8.0. 6 | 7 | #### Changes 8 | 9 | Eureka 2.0.0 includes complete Swift 3 Compatibility and adopts the new [API Design Guidelines](https://swift.org/documentation/api-design-guidelines/). It also includes the whole new validations build-in feature. 10 | Bring support to swift 3 involves some API updates to follow Apple's Swift API best practices, we have also changed and deprecated some API's. 11 | 12 | Most important changes will be listed below... 13 | 14 | 15 | Many properties, methods, types were renamed and Xcode should suggest the fix automatically. 16 | 17 | 18 | 19 | These are some examples: 20 | 21 | |Old API| New API| 22 | |----|----| 23 | |`func rowByTag(_: String) -> RowOf?`|`func rowBy(tag: String) -> RowOf?`| 24 | |`func rowByTag(_: String) -> Row?`|`func rowBy(tag: String) -> Row?`| 25 | |`func rowByTag(_: String) -> BaseRow?`|`func rowBy(tag: String) -> BaseRow?`| 26 | |`func sectionByTag(_: String) -> Section?`|`func sectionBy(tag: String) -> Section?`| 27 | |`func rowValueHasBeenChanged(_: BaseRow, oldValue: Any?, newValue: Any?)`|`func valueHasBeenChanged(for: BaseRow, oldValue: Any?, newValue: Any?)`| 28 | |`public final func indexPath() -> IndexPath?`|`public final var indexPath: IndexPath?`| 29 | |`func prepareForSegue(_ segue: UIStoryboardSegue)`|`func prepare(for segue: UIStoryboardSegue)`| 30 | |`func presentViewController(_ viewController: VCType!, row: BaseRow, presentingViewController:FormViewController)`|`present(_ viewController: VCType!, row: BaseRow, presentingViewController:FormViewController)`| 31 | |`func createController() -> VCType?`|`func makeController() -> VCType?`| 32 | 33 | 34 | There are also some breaking changes related with deprecated API: 35 | 36 | Removed APIs: 37 | 38 | * `PostalAddressRow` and `ImageRow` was deleted. You can find them and many other custom rows at EurekaCommunity [organization account](https://github.com/eurekaCommunity). 39 | * `highlightCell` and `unhighlightCell` callbacks were deleted, now we should use `row.isHighlighted` from cell update to check from highlighted status and make UI modification according its value. 40 | 41 | In case you want to do something when the row's highlighted state switches its value you can set up `onCellHighlightChanged` callback. 42 | 43 | Custom Rows changes: 44 | 45 | Row generic type no longer specify the value type. Its Value type is inferred from cell specification. 46 | 47 | Before: 48 | 49 | `public final class WeekDayRow: Row, WeekDayCell>, RowType` 50 | 51 | 52 | After: 53 | 54 | `public final class WeekDayRow: Row, RowType` 55 | -------------------------------------------------------------------------------- /Eureka.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Eureka.playground/playground.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Eureka.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Eureka.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Eureka.png -------------------------------------------------------------------------------- /Eureka.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Eureka' 3 | s.version = '5.5.0' 4 | s.license = 'MIT' 5 | s.summary = 'Elegant iOS Forms in pure Swift' 6 | s.homepage = 'https://github.com/xmartlabs/Eureka' 7 | s.social_media_url = 'http://twitter.com/xmartlabs' 8 | s.authors = { 'Martin Barreto' => 'martin@xmartlabs.com', 'Mathias Claassen' => 'mathias@xmartlabs.com' } 9 | s.source = { :git => 'https://github.com/xmartlabs/Eureka.git', :tag => s.version } 10 | s.ios.deployment_target = '9.0' 11 | s.ios.frameworks = 'UIKit', 'Foundation' 12 | s.source_files = 'Source/**/*.swift' 13 | s.requires_arc = true 14 | s.swift_version = '5.0' 15 | end 16 | -------------------------------------------------------------------------------- /Eureka.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Eureka.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Eureka.xcodeproj/xcshareddata/xcschemes/Eureka.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 63 | 69 | 70 | 71 | 72 | 78 | 79 | 85 | 86 | 87 | 88 | 90 | 91 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /Eureka.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Eureka.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 42 | 48 | 49 | 50 | 51 | 52 | 62 | 64 | 70 | 71 | 72 | 73 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Example/EmojiCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // AppDelegate.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import UIKit 26 | 27 | @UIApplicationMain 28 | class AppDelegate: UIResponder, UIApplicationDelegate { 29 | 30 | var window: UIWindow? 31 | 32 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { 33 | // Take a look at Main.storyboard 34 | return true 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "appIcon20pt@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "appIcon20pt@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "appIcon29pt@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "appIcon29pt@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "appIcon29pt@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "appIcon40pt@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "appIcon40pt@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "idiom" : "iphone", 47 | "size" : "57x57", 48 | "scale" : "1x" 49 | }, 50 | { 51 | "idiom" : "iphone", 52 | "size" : "57x57", 53 | "scale" : "2x" 54 | }, 55 | { 56 | "size" : "60x60", 57 | "idiom" : "iphone", 58 | "filename" : "appIcon60pt@2x.png", 59 | "scale" : "2x" 60 | }, 61 | { 62 | "size" : "60x60", 63 | "idiom" : "iphone", 64 | "filename" : "appIcon60pt@3x.png", 65 | "scale" : "3x" 66 | }, 67 | { 68 | "idiom" : "ipad", 69 | "size" : "20x20", 70 | "scale" : "1x" 71 | }, 72 | { 73 | "idiom" : "ipad", 74 | "size" : "20x20", 75 | "scale" : "2x" 76 | }, 77 | { 78 | "idiom" : "ipad", 79 | "size" : "29x29", 80 | "scale" : "1x" 81 | }, 82 | { 83 | "idiom" : "ipad", 84 | "size" : "29x29", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "idiom" : "ipad", 89 | "size" : "40x40", 90 | "scale" : "1x" 91 | }, 92 | { 93 | "idiom" : "ipad", 94 | "size" : "40x40", 95 | "scale" : "2x" 96 | }, 97 | { 98 | "idiom" : "ipad", 99 | "size" : "50x50", 100 | "scale" : "1x" 101 | }, 102 | { 103 | "idiom" : "ipad", 104 | "size" : "50x50", 105 | "scale" : "2x" 106 | }, 107 | { 108 | "idiom" : "ipad", 109 | "size" : "72x72", 110 | "scale" : "1x" 111 | }, 112 | { 113 | "idiom" : "ipad", 114 | "size" : "72x72", 115 | "scale" : "2x" 116 | }, 117 | { 118 | "size" : "76x76", 119 | "idiom" : "ipad", 120 | "filename" : "appIcon76pt@1x.png", 121 | "scale" : "1x" 122 | }, 123 | { 124 | "size" : "76x76", 125 | "idiom" : "ipad", 126 | "filename" : "appIcon76pt@2x.png", 127 | "scale" : "2x" 128 | }, 129 | { 130 | "size" : "83.5x83.5", 131 | "idiom" : "ipad", 132 | "filename" : "appIcon83-5pt@2x.png", 133 | "scale" : "2x" 134 | }, 135 | { 136 | "idiom" : "ios-marketing", 137 | "size" : "1024x1024", 138 | "scale" : "1x" 139 | } 140 | ], 141 | "info" : { 142 | "version" : 1, 143 | "author" : "xcode" 144 | } 145 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon20pt@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@1x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon29pt@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon40pt@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon60pt@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon76pt@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon76pt@1x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon76pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon76pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon83-5pt@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/AppIcon.appiconset/appIcon83-5pt@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Eureka.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Eureka@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/Eureka.imageset/Eureka@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/Eureka.imageset/Eureka@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/checkedDay.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "checkedDay.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/checkedDay.imageset/checkedDay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/checkedDay.imageset/checkedDay.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/map_pin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "map_pin@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "map_pin@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/map_pin.imageset/map_pin@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/map_pin.imageset/map_pin@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/map_pin.imageset/map_pin@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/map_pin.imageset/map_pin@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/plus_image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "plus_image@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "plus_image@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/plus_image.imageset/plus_image@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/plus_image.imageset/plus_image@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/plus_image.imageset/plus_image@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/plus_image.imageset/plus_image@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "selectedCircle@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "selectedCircle@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selected.imageset/selectedCircle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/selected.imageset/selectedCircle@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selected.imageset/selectedCircle@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/selected.imageset/selectedCircle@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selectedRectangle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "selectedRectangle@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "selectedRectangle@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selectedRectangle.imageset/selectedRectangle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/selectedRectangle.imageset/selectedRectangle@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/selectedRectangle.imageset/selectedRectangle@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/selectedRectangle.imageset/selectedRectangle@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/uncheckedDay.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "uncheckedDay.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/uncheckedDay.imageset/uncheckedDay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/uncheckedDay.imageset/uncheckedDay.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselected.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "unselectedCircle@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "unselectedCircle@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselected.imageset/unselectedCircle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/unselected.imageset/unselectedCircle@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselected.imageset/unselectedCircle@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/unselected.imageset/unselectedCircle@3x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselectedRectangle.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "unselectedRectangle@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "unselectedRectangle@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselectedRectangle.imageset/unselectedRectangle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/unselectedRectangle.imageset/unselectedRectangle@2x.png -------------------------------------------------------------------------------- /Example/Example/Assets.xcassets/unselectedRectangle.imageset/unselectedRectangle@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Example/Assets.xcassets/unselectedRectangle.imageset/unselectedRectangle@3x.png -------------------------------------------------------------------------------- /Example/Example/Base.lproj/EurekaSectionHeader.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Example/Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Example/Controllers/CustomCellsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomCellsViewController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | //MARK: Custom Cells Example 11 | 12 | class CustomCellsController : FormViewController { 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | form +++ 18 | Section() { 19 | var header = HeaderFooterView(.nibFile(name: "EurekaSectionHeader", bundle: nil)) 20 | header.onSetupView = { (view, section) -> () in 21 | view.imageView.alpha = 0; 22 | UIView.animate(withDuration: 2.0, animations: { [weak view] in 23 | view?.imageView.alpha = 1 24 | }) 25 | view.layer.transform = CATransform3DMakeScale(0.9, 0.9, 1) 26 | UIView.animate(withDuration: 1.0, animations: { [weak view] in 27 | view?.layer.transform = CATransform3DIdentity 28 | }) 29 | } 30 | $0.header = header 31 | } 32 | +++ Section("WeekDay cell") 33 | 34 | <<< WeekDayRow(){ 35 | $0.value = [.monday, .wednesday, .friday] 36 | } 37 | 38 | <<< TextFloatLabelRow() { 39 | $0.title = "Float Label Row, type something to see.." 40 | } 41 | 42 | <<< IntFloatLabelRow() { 43 | $0.title = "Float Label Row, type something to see.." 44 | } 45 | } 46 | 47 | } 48 | 49 | class EurekaLogoViewNib: UIView { 50 | 51 | @IBOutlet weak var imageView: UIImageView! 52 | 53 | required init?(coder aDecoder: NSCoder) { 54 | super.init(coder: aDecoder) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Example/Example/Controllers/CustomDesignController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomDesignController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class CustomDesignController: FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | form +++ 16 | Section() 17 | <<< SwitchRow() { 18 | $0.cellProvider = CellProvider(nibName: "SwitchCell", bundle: Bundle.main) 19 | }.cellSetup { (cell, row) in 20 | cell.height = { 67 } 21 | } 22 | 23 | <<< DatePickerRow() { 24 | $0.cellProvider = CellProvider(nibName: "DatePickerCell", bundle: Bundle.main) 25 | }.cellSetup { (cell, row) in 26 | cell.height = { 345 } 27 | } 28 | 29 | <<< TextRow() { 30 | $0.cellProvider = CellProvider(nibName: "TextCell", bundle: Bundle.main) 31 | }.cellSetup { (cell, row) in 32 | cell.height = { 199 } 33 | } 34 | .onChange { row in 35 | if let textView = row.cell.viewWithTag(99) as? UITextView { 36 | textView.text = row.cell.textField.text 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Example/Example/Controllers/DisabledRowsExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DisabledRowsExample.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class DisabledRowsExample : FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | form = Section() 17 | 18 | <<< SegmentedRow("segments"){ 19 | $0.options = ["Enabled", "Disabled"] 20 | $0.value = "Disabled" 21 | } 22 | 23 | <<< TextRow(){ 24 | $0.title = "choose enabled, disable above..." 25 | $0.disabled = "$segments = 'Disabled'" 26 | } 27 | 28 | <<< SwitchRow("Disable Next Section?"){ 29 | $0.title = $0.tag 30 | $0.disabled = "$segments = 'Disabled'" 31 | } 32 | 33 | +++ Section() 34 | 35 | <<< TextRow() { 36 | $0.title = "Gonna be disabled soon.." 37 | $0.disabled = Eureka.Condition.function(["Disable Next Section?"], { (form) -> Bool in 38 | let row: SwitchRow! = form.rowBy(tag: "Disable Next Section?") 39 | return row.value ?? false 40 | }) 41 | } 42 | 43 | +++ Section() 44 | 45 | <<< SegmentedRow(){ 46 | $0.options = ["Always Disabled"] 47 | $0.disabled = true 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Example/Example/Controllers/FieldRowCustomizationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FieldRowCustomizationController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class FieldRowCustomizationController : FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | form +++ 16 | Section(header: "Default field rows", footer: "Rows with title have a right-aligned text field.\nRows without title have a left-aligned text field.\nBut this can be changed...") 17 | 18 | <<< NameRow() { 19 | $0.title = "Your name:" 20 | $0.placeholder = "(right alignment)" 21 | } 22 | .cellSetup { cell, row in 23 | cell.imageView?.image = UIImage(named: "plus_image") 24 | } 25 | 26 | <<< NameRow() { 27 | $0.placeholder = "Name (left alignment)" 28 | } 29 | .cellSetup { cell, row in 30 | cell.imageView?.image = UIImage(named: "plus_image") 31 | } 32 | 33 | +++ Section("Customized Alignment") 34 | 35 | <<< NameRow() { 36 | $0.title = "Your name:" 37 | }.cellUpdate { cell, row in 38 | cell.textField.textAlignment = .left 39 | cell.textField.placeholder = "(left alignment)" 40 | } 41 | 42 | <<< NameRow().cellUpdate { cell, row in 43 | cell.textField.textAlignment = .right 44 | cell.textField.placeholder = "Name (right alignment)" 45 | } 46 | 47 | +++ Section(header: "Customized Text field width", footer: "Eureka allows us to set up a specific UITextField width using textFieldPercentage property. In the section above we have also right aligned the textLabels.") 48 | 49 | <<< NameRow() { 50 | $0.title = "Title" 51 | $0.titlePercentage = 0.4 52 | $0.placeholder = "textFieldPercentage = 0.6" 53 | } 54 | .cellUpdate { 55 | $1.cell.textField.textAlignment = .left 56 | $1.cell.textLabel?.textAlignment = .right 57 | } 58 | <<< NameRow() { 59 | $0.title = "Another Title" 60 | $0.titlePercentage = 0.4 61 | $0.placeholder = "textFieldPercentage = 0.6" 62 | } 63 | .cellUpdate { 64 | $1.cell.textField.textAlignment = .left 65 | $1.cell.textLabel?.textAlignment = .right 66 | } 67 | <<< NameRow() { 68 | $0.title = "One more" 69 | $0.titlePercentage = 0.3 70 | $0.placeholder = "textFieldPercentage = 0.7" 71 | } 72 | .cellUpdate { 73 | $1.cell.textField.textAlignment = .left 74 | $1.cell.textLabel?.textAlignment = .right 75 | } 76 | 77 | +++ Section("TextAreaRow") 78 | 79 | <<< TextAreaRow() { 80 | $0.placeholder = "TextAreaRow" 81 | $0.textAreaHeight = .dynamic(initialTextViewHeight: 110) 82 | } 83 | <<< TextAreaRow() { 84 | $0.value = "You also have scrollable read only textAreaRows! I have to write a big text so you will be able to scroll a lot and see that this row is scrollable. I think it is a good idea to insert a Lorem Ipsum here: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac odio consectetur, faucibus elit at, congue dolor. Duis quis magna eu ante egestas laoreet. Vivamus ultricies tristique porttitor. Proin viverra sem non turpis molestie, volutpat facilisis justo rutrum. Nulla eget commodo ligula. Aliquam lobortis lobortis justo id fermentum. Sed sit amet elit eu ipsum ultricies porttitor et sed justo. Fusce id mi aliquam, iaculis odio ac, tempus sem. Aenean in eros imperdiet, euismod lacus vitae, mattis nulla. Praesent ornare sem vitae ornare efficitur. Nullam dictum tortor a tortor vestibulum pharetra. Donec sollicitudin varius fringilla. Praesent posuere fringilla tristique. Aliquam dapibus vel nisi in sollicitudin. In eu ligula arcu." 85 | $0.textAreaMode = .readOnly 86 | $0.textAreaHeight = .fixed(cellHeight: 110) 87 | } 88 | 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Example/Example/Controllers/FormatterExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormatterExample.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class FormatterExample : FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | form +++ Section("Number formatters") 17 | <<< DecimalRow(){ 18 | $0.useFormatterDuringInput = true 19 | $0.title = "Currency style" 20 | $0.value = 2015 21 | let formatter = CurrencyFormatter() 22 | formatter.locale = .current 23 | formatter.numberStyle = .currency 24 | $0.formatter = formatter 25 | } 26 | <<< DecimalRow(){ 27 | $0.title = "Scientific style" 28 | $0.value = 2015 29 | let formatter = NumberFormatter() 30 | formatter.locale = .current 31 | formatter.numberStyle = .scientific 32 | $0.formatter = formatter 33 | } 34 | <<< IntRow(){ 35 | $0.title = "Spell out style" 36 | $0.value = 2015 37 | let formatter = NumberFormatter() 38 | formatter.locale = .current 39 | formatter.numberStyle = .spellOut 40 | $0.formatter = formatter 41 | } 42 | +++ Section("Date formatters") 43 | <<< DateRow(){ 44 | $0.title = "Short style" 45 | $0.value = Date() 46 | let formatter = DateFormatter() 47 | formatter.locale = .current 48 | formatter.dateStyle = .short 49 | $0.dateFormatter = formatter 50 | } 51 | <<< DateRow(){ 52 | $0.title = "Long style" 53 | $0.value = Date() 54 | let formatter = DateFormatter() 55 | formatter.locale = .current 56 | formatter.dateStyle = .long 57 | $0.dateFormatter = formatter 58 | } 59 | +++ Section("Other formatters") 60 | <<< DecimalRow(){ 61 | $0.title = "Energy: Jules to calories" 62 | $0.value = 100.0 63 | let formatter = EnergyFormatter() 64 | $0.formatter = formatter 65 | } 66 | <<< IntRow(){ 67 | $0.title = "Weight: Kg to lb" 68 | $0.value = 1000 69 | $0.formatter = MassFormatter() 70 | } 71 | } 72 | 73 | class CurrencyFormatter : NumberFormatter, FormatterProtocol { 74 | override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer?, for string: String, range rangep: UnsafeMutablePointer?) throws { 75 | guard obj != nil else { return } 76 | var str = string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "") 77 | if !string.isEmpty, numberStyle == .currency && !string.contains(currencySymbol) { 78 | // Check if the currency symbol is at the last index 79 | if let formattedNumber = self.string(from: 1), String(formattedNumber[formattedNumber.index(before: formattedNumber.endIndex)...]) == currencySymbol { 80 | // This means the user has deleted the currency symbol. We cut the last number and then add the symbol automatically 81 | str = String(str[.. UITextPosition { 89 | return textInput.position(from: position, offset:((newValue?.count ?? 0) - (oldValue?.count ?? 0))) ?? position 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Example/Example/Controllers/HiddenRowsExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HiddenRowsExample.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class HiddenRowsExample : FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | TextRow.defaultCellUpdate = { cell, row in 17 | cell.textLabel?.font = UIFont.italicSystemFont(ofSize: 12) 18 | } 19 | 20 | form = Section("What do you want to talk about:") 21 | <<< SegmentedRow("segments"){ 22 | $0.options = ["Sport", "Music", "Films"] 23 | $0.value = "Films" 24 | } 25 | +++ Section(){ 26 | $0.tag = "sport_s" 27 | $0.hidden = "$segments != 'Sport'" // .Predicate(NSPredicate(format: "$segments != 'Sport'")) 28 | } 29 | <<< TextRow(){ 30 | $0.title = "Which is your favourite soccer player?" 31 | } 32 | 33 | <<< TextRow(){ 34 | $0.title = "Which is your favourite coach?" 35 | } 36 | 37 | <<< TextRow(){ 38 | $0.title = "Which is your favourite team?" 39 | } 40 | 41 | +++ Section(){ 42 | $0.tag = "music_s" 43 | $0.hidden = "$segments != 'Music'" 44 | } 45 | <<< TextRow(){ 46 | $0.title = "Which music style do you like most?" 47 | } 48 | 49 | <<< TextRow(){ 50 | $0.title = "Which is your favourite singer?" 51 | } 52 | <<< TextRow(){ 53 | $0.title = "How many CDs have you got?" 54 | } 55 | 56 | +++ Section(){ 57 | $0.tag = "films_s" 58 | $0.hidden = "$segments != 'Films'" 59 | } 60 | <<< TextRow(){ 61 | $0.title = "Which is your favourite actor?" 62 | } 63 | 64 | <<< TextRow(){ 65 | $0.title = "Which is your favourite film?" 66 | } 67 | 68 | +++ Section() 69 | 70 | <<< SwitchRow("Show Next Row"){ 71 | $0.title = $0.tag 72 | } 73 | <<< SwitchRow("Show Next Section"){ 74 | $0.title = $0.tag 75 | $0.hidden = .function(["Show Next Row"], { form -> Bool in 76 | let row: RowOf! = form.rowBy(tag: "Show Next Row") 77 | return row.value ?? false == false 78 | }) 79 | } 80 | 81 | +++ Section(footer: "This section is shown only when 'Show Next Row' switch is enabled"){ 82 | $0.hidden = .function(["Show Next Section"], { form -> Bool in 83 | let row: RowOf! = form.rowBy(tag: "Show Next Section") 84 | return row.value ?? false == false 85 | }) 86 | } 87 | <<< TextRow() { 88 | $0.placeholder = "Gonna dissapear soon!!" 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Example/Example/Controllers/InlineRowsExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InlineRowsExample.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class InlineRowsController: FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | form.inlineRowHideOptions = InlineRowHideOptions.AnotherInlineRowIsShown.union(.FirstResponderChanges) 17 | 18 | form 19 | 20 | +++ Section("Automatically Hide Inline Rows?") 21 | 22 | <<< SwitchRow() { 23 | $0.title = "Hides when another inline row is shown" 24 | $0.value = true 25 | } 26 | .onChange { [weak form] in 27 | if $0.value == true { 28 | form?.inlineRowHideOptions = form?.inlineRowHideOptions?.union(.AnotherInlineRowIsShown) 29 | } 30 | else { 31 | form?.inlineRowHideOptions = form?.inlineRowHideOptions?.subtracting(.AnotherInlineRowIsShown) 32 | } 33 | } 34 | 35 | <<< SwitchRow() { 36 | $0.title = "Hides when the First Responder changes" 37 | $0.value = true 38 | } 39 | .onChange { [weak form] in 40 | if $0.value == true { 41 | form?.inlineRowHideOptions = form?.inlineRowHideOptions?.union(.FirstResponderChanges) 42 | } 43 | else { 44 | form?.inlineRowHideOptions = form?.inlineRowHideOptions?.subtracting(.FirstResponderChanges) 45 | } 46 | } 47 | 48 | +++ Section() 49 | 50 | <<< DateInlineRow() { 51 | $0.title = "DateInlineRow" 52 | $0.value = Date() 53 | } 54 | 55 | <<< TimeInlineRow(){ 56 | $0.title = "TimeInlineRow" 57 | $0.value = Date() 58 | } 59 | 60 | <<< DateTimeInlineRow(){ 61 | $0.title = "DateTimeInlineRow" 62 | $0.value = Date() 63 | } 64 | 65 | <<< CountDownInlineRow(){ 66 | $0.title = "CountDownInlineRow" 67 | var dateComp = DateComponents() 68 | dateComp.hour = 18 69 | dateComp.minute = 33 70 | dateComp.timeZone = TimeZone.current 71 | $0.value = Calendar.current.date(from: dateComp) 72 | } 73 | 74 | +++ Section("Generic inline picker") 75 | 76 | <<< PickerInlineRow("PickerInlineRow") { (row : PickerInlineRow) -> Void in 77 | row.title = row.tag 78 | row.displayValueFor = { (rowValue: Date?) in 79 | return rowValue.map { "Year \(Calendar.current.component(.year, from: $0))" } 80 | } 81 | row.options = [] 82 | var date = Date() 83 | for _ in 1...10{ 84 | row.options.append(date) 85 | date = date.addingTimeInterval(60*60*24*365) 86 | } 87 | row.value = row.options[0] 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Example/Example/Controllers/ListSectionsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListSectionsController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class ListSectionsController: FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | let continents = ["Africa", "Antarctica", "Asia", "Australia", "Europe", "North America", "South America"] 17 | 18 | form +++ SelectableSection>() { section in 19 | section.header = HeaderFooterView(title: "Where do you live?") 20 | } 21 | 22 | for option in continents { 23 | form.last! <<< ImageCheckRow(option){ lrow in 24 | lrow.title = option 25 | lrow.selectableValue = option 26 | lrow.value = nil 27 | } 28 | } 29 | 30 | let oceans = ["Arctic", "Atlantic", "Indian", "Pacific", "Southern"] 31 | 32 | form +++ SelectableSection>("And which of the following oceans have you taken a bath in?", selectionType: .multipleSelection) 33 | for option in oceans { 34 | form.last! <<< ImageCheckRow(option){ lrow in 35 | lrow.title = option 36 | lrow.selectableValue = option 37 | lrow.value = nil 38 | }.cellSetup { cell, _ in 39 | cell.trueImage = UIImage(named: "selectedRectangle")! 40 | cell.falseImage = UIImage(named: "unselectedRectangle")! 41 | cell.accessoryType = .checkmark 42 | } 43 | } 44 | } 45 | 46 | override func valueHasBeenChanged(for row: BaseRow, oldValue: Any?, newValue: Any?) { 47 | if row.section === form[0] { 48 | print("Single Selection:\((row.section as! SelectableSection>).selectedRow()?.baseValue ?? "No row selected")") 49 | } 50 | else if row.section === form[1] { 51 | print("Mutiple Selection:\((row.section as! SelectableSection>).selectedRows().map({$0.baseValue}))") 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Example/Example/Controllers/NavigationAccessoryController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationAccessoryController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class NavigationAccessoryController : FormViewController { 12 | 13 | var navigationOptionsBackup : RowNavigationOptions? 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | navigationOptions = RowNavigationOptions.Enabled.union(.SkipCanNotBecomeFirstResponderRow) 19 | navigationOptionsBackup = navigationOptions 20 | 21 | form = Section(header: "Settings", footer: "These settings change how the navigation accessory view behaves") 22 | 23 | <<< SwitchRow("set_none") { [weak self] in 24 | $0.title = "Navigation accessory view" 25 | $0.value = self?.navigationOptions != .Disabled 26 | }.onChange { [weak self] in 27 | if $0.value ?? false { 28 | self?.navigationOptions = self?.navigationOptionsBackup 29 | self?.form.rowBy(tag: "set_disabled")?.baseValue = self?.navigationOptions?.contains(.StopDisabledRow) 30 | self?.form.rowBy(tag: "set_skip")?.baseValue = self?.navigationOptions?.contains(.SkipCanNotBecomeFirstResponderRow) 31 | self?.form.rowBy(tag: "set_disabled")?.updateCell() 32 | self?.form.rowBy(tag: "set_skip")?.updateCell() 33 | } 34 | else { 35 | self?.navigationOptionsBackup = self?.navigationOptions 36 | self?.navigationOptions = .Disabled 37 | } 38 | } 39 | 40 | <<< CheckRow("set_disabled") { [weak self] in 41 | $0.title = "Stop at disabled row" 42 | $0.value = self?.navigationOptions?.contains(.StopDisabledRow) 43 | $0.hidden = "$set_none == false" // .Predicate(NSPredicate(format: "$set_none == false")) 44 | }.onChange { [weak self] row in 45 | if row.value ?? false { 46 | self?.navigationOptions = self?.navigationOptions?.union(.StopDisabledRow) 47 | } 48 | else{ 49 | self?.navigationOptions = self?.navigationOptions?.subtracting(.StopDisabledRow) 50 | } 51 | } 52 | 53 | <<< CheckRow("set_skip") { [weak self] in 54 | $0.title = "Skip non first responder view" 55 | $0.value = self?.navigationOptions?.contains(.SkipCanNotBecomeFirstResponderRow) 56 | $0.hidden = "$set_none == false" 57 | }.onChange { [weak self] row in 58 | if row.value ?? false { 59 | self?.navigationOptions = self?.navigationOptions?.union(.SkipCanNotBecomeFirstResponderRow) 60 | } 61 | else{ 62 | self?.navigationOptions = self?.navigationOptions?.subtracting(.SkipCanNotBecomeFirstResponderRow) 63 | } 64 | } 65 | 66 | 67 | +++ 68 | 69 | NameRow() { $0.title = "Your name:" } 70 | 71 | <<< PasswordRow() { $0.title = "Your password:" } 72 | 73 | +++ 74 | Section() 75 | 76 | <<< SegmentedRow() { 77 | $0.title = "Favourite food:" 78 | $0.options = [🐗, 🐖, 🐡, 🍐] 79 | } 80 | 81 | <<< PhoneRow() { $0.title = "Your phone number" } 82 | 83 | <<< URLRow() { 84 | $0.title = "Disabled" 85 | $0.disabled = true 86 | } 87 | 88 | <<< TextRow() { $0.title = "Your father's name"} 89 | 90 | <<< TextRow(){ $0.title = "Your mother's name"} 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Example/Example/Controllers/PlainTableViewExample.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlainTableViewExample.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class PlainTableViewStyleController : FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | form +++ 17 | 18 | Section() 19 | 20 | <<< TextRow() { 21 | $0.title = "Name" 22 | $0.value = "John Doe" 23 | } 24 | 25 | <<< TextRow() { 26 | $0.title = "Username" 27 | $0.value = "johndoe1" 28 | } 29 | 30 | <<< EmailRow() { 31 | $0.title = "Email Address" 32 | $0.value = "john@doe.com" 33 | } 34 | 35 | <<< PasswordRow() { 36 | $0.title = "Password" 37 | $0.value = "johndoe9876" 38 | } 39 | 40 | // Remove excess separator lines on non-existent cells 41 | tableView.tableFooterView = UIView() 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Example/Example/Controllers/SwipeActionsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwipeActionsController.swift 3 | // Example 4 | // 5 | // Created by Mathias Claassen on 3/15/18. 6 | // Copyright © 2018 Xmartlabs. All rights reserved. 7 | // 8 | 9 | import Eureka 10 | 11 | class SwipeActionsController: FormViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | form +++ Section(footer: "Eureka sets table.isEditing = true only if the form contains a MultivaluedSection. SwipeActions only work when isEditing = false, therefore you have to set that in ViewWillAppear. Both can't be used on the same form.") 17 | <<< LabelRow("Actions Right: iOS >= 7") { 18 | $0.title = $0.tag 19 | 20 | let moreAction = SwipeAction(style: .normal, title: "More", handler: { (action, row, completionHandler) in 21 | print("More") 22 | completionHandler?(true) 23 | }) 24 | 25 | let deleteAction = SwipeAction(style: .destructive, title: "Delete") { (action, row, completionHandler) in 26 | print("Delete") 27 | completionHandler?(true) 28 | } 29 | 30 | $0.trailingSwipe.actions = [deleteAction,moreAction] 31 | 32 | } 33 | 34 | <<< LabelRow("Actions Left & Right: iOS >= 11") { 35 | $0.title = $0.tag 36 | 37 | let moreAction = SwipeAction(style: .normal, title: "More") { (action, row, completionHandler) in 38 | print("More") 39 | completionHandler?(true) 40 | } 41 | 42 | let deleteAction = SwipeAction(style: .destructive, title: "Delete", handler: { (action, row, completionHandler) in 43 | print("Delete") 44 | completionHandler?(true) 45 | }) 46 | 47 | $0.trailingSwipe.actions = [deleteAction,moreAction] 48 | $0.trailingSwipe.performsFirstActionWithFullSwipe = true 49 | 50 | if #available(iOS 11,*) { 51 | let infoAction = SwipeAction(style: .normal, title: "Info", handler: { (action, row, completionHandler) in 52 | print("Info") 53 | completionHandler?(true) 54 | }) 55 | infoAction.actionBackgroundColor = .blue 56 | 57 | $0.leadingSwipe.actions = [infoAction] 58 | $0.leadingSwipe.performsFirstActionWithFullSwipe = true 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Example/Example/CustomDesign/DatePickerCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Example/Example/CustomDesign/SwitchCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Example/CustomRows/ImageRow/ImagePickerController.swift: -------------------------------------------------------------------------------- 1 | // ImagePickerController.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import Eureka 27 | 28 | /// Selector Controller used to pick an image 29 | open class ImagePickerController : UIImagePickerController, TypedRowControllerType, UIImagePickerControllerDelegate, UINavigationControllerDelegate { 30 | 31 | /// The row that pushed or presented this controller 32 | public var row: RowOf! 33 | 34 | /// A closure to be called when the controller disappears. 35 | public var onDismissCallback : ((UIViewController) -> ())? 36 | 37 | open override func viewDidLoad() { 38 | super.viewDidLoad() 39 | delegate = self 40 | } 41 | 42 | open func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { 43 | (row as? ImageRow)?.imageURL = info[.referenceURL] as? URL 44 | row.value = info[.originalImage] as? UIImage 45 | onDismissCallback?(self) 46 | } 47 | 48 | open func imagePickerControllerDidCancel(_ picker: UIImagePickerController){ 49 | onDismissCallback?(self) 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Eureka 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 5.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSCameraUsageDescription 26 | ImageRow example 27 | NSPhotoLibraryUsageDescription 28 | Show ImageRow example 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | UIInterfaceOrientationPortraitUpsideDown 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Example/Media/CatalogFieldRows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/CatalogFieldRows.jpg -------------------------------------------------------------------------------- /Example/Media/EurekaAlertRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaAlertRow.gif -------------------------------------------------------------------------------- /Example/Media/EurekaCustomCellDisabled.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaCustomCellDisabled.gif -------------------------------------------------------------------------------- /Example/Media/EurekaCustomCells.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaCustomCells.gif -------------------------------------------------------------------------------- /Example/Media/EurekaCustomRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaCustomRow.gif -------------------------------------------------------------------------------- /Example/Media/EurekaExample1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaExample1.gif -------------------------------------------------------------------------------- /Example/Media/EurekaExample2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaExample2.gif -------------------------------------------------------------------------------- /Example/Media/EurekaExample3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaExample3.gif -------------------------------------------------------------------------------- /Example/Media/EurekaHidden.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaHidden.gif -------------------------------------------------------------------------------- /Example/Media/EurekaHowTo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaHowTo.gif -------------------------------------------------------------------------------- /Example/Media/EurekaLocationRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaLocationRow.gif -------------------------------------------------------------------------------- /Example/Media/EurekaMultivalued.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaMultivalued.gif -------------------------------------------------------------------------------- /Example/Media/EurekaNavigation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaNavigation.gif -------------------------------------------------------------------------------- /Example/Media/EurekaOnChange.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaOnChange.gif -------------------------------------------------------------------------------- /Example/Media/EurekaRows.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaRows.gif -------------------------------------------------------------------------------- /Example/Media/EurekaSegmentedRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaSegmentedRow.gif -------------------------------------------------------------------------------- /Example/Media/EurekaSwitchSections.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/EurekaSwitchSections.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaCountDownInlineRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaCountDownInlineRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaCountDownPickerRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaCountDownPickerRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaCountDownRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaCountDownRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDateInlineRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDateInlineRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDatePickerRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDatePickerRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDateRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDateRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDateTimeInlineRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDateTimeInlineRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDateTimePickerRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDateTimePickerRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaDateTimeRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaDateTimeRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaTimeInlineRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaTimeInlineRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaTimePickerRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaTimePickerRow.gif -------------------------------------------------------------------------------- /Example/Media/RowGifs/EurekaTimeRow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowGifs/EurekaTimeRow.gif -------------------------------------------------------------------------------- /Example/Media/RowStatics/ActionSheetRow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/ActionSheetRow.jpeg -------------------------------------------------------------------------------- /Example/Media/RowStatics/AlertRow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/AlertRow.jpeg -------------------------------------------------------------------------------- /Example/Media/RowStatics/ButtonRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/ButtonRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/CheckRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/CheckRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/ImageRow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/ImageRow.jpeg -------------------------------------------------------------------------------- /Example/Media/RowStatics/LabelRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/LabelRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/MultipleSelectorRow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/MultipleSelectorRow.jpeg -------------------------------------------------------------------------------- /Example/Media/RowStatics/PickerRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/PickerRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/PictureRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/PictureRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/PostalAddressRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/PostalAddressRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/PushRow.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/PushRow.jpeg -------------------------------------------------------------------------------- /Example/Media/RowStatics/SegmentedRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/SegmentedRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/SegmentedRowWithTitle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/SegmentedRowWithTitle.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/SliderRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/SliderRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/StepperRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/StepperRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/SwitchRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/SwitchRow.png -------------------------------------------------------------------------------- /Example/Media/RowStatics/TextAreaRow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/Example/Media/RowStatics/TextAreaRow.png -------------------------------------------------------------------------------- /Example/UITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 XMARTLABS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "Eureka", 6 | platforms: [.iOS(.v9)], 7 | products: [ 8 | .library(name: "Eureka", targets: ["Eureka"]) 9 | ], 10 | targets: [ 11 | .target( 12 | name: "Eureka", 13 | path: "Source" 14 | ), 15 | .testTarget( 16 | name: "EurekaTests", 17 | dependencies: ["Eureka"], 18 | path: "Tests" 19 | ) 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /Source/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Source/Core/CellType.swift: -------------------------------------------------------------------------------- 1 | // CellType.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | // MARK: Cell Protocols 29 | 30 | public protocol BaseCellType : AnyObject { 31 | 32 | /// Method that will return the height of the cell 33 | var height : (() -> CGFloat)? { get } 34 | 35 | /** 36 | Method called once when creating a cell. Responsible for setting up the cell. 37 | */ 38 | func setup() 39 | 40 | /** 41 | Method called each time the cell is updated (e.g. 'cellForRowAtIndexPath' is called). Responsible for updating the cell. 42 | */ 43 | func update() 44 | 45 | /** 46 | Method called each time the cell is selected (tapped on by the user). 47 | */ 48 | func didSelect() 49 | 50 | /** 51 | Called when cell is about to become first responder 52 | 53 | - returns: If the cell should become first responder. 54 | */ 55 | func cellCanBecomeFirstResponder() -> Bool 56 | 57 | /** 58 | Method called when the cell becomes first responder 59 | */ 60 | func cellBecomeFirstResponder(withDirection: Direction) -> Bool 61 | 62 | /** 63 | Method called when the cell resigns first responder 64 | */ 65 | func cellResignFirstResponder() -> Bool 66 | 67 | /** 68 | A reference to the controller in which the cell is displayed. 69 | */ 70 | func formViewController () -> FormViewController? 71 | } 72 | 73 | public protocol TypedCellType: BaseCellType { 74 | 75 | associatedtype Value: Equatable 76 | 77 | /// The row associated to this cell. 78 | var row: RowOf! { get set } 79 | } 80 | 81 | public protocol CellType: TypedCellType {} 82 | -------------------------------------------------------------------------------- /Source/Core/Helpers.swift: -------------------------------------------------------------------------------- 1 | // Helpers.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | extension UIView { 29 | 30 | public func findFirstResponder() -> UIView? { 31 | if isFirstResponder { return self } 32 | for subView in subviews { 33 | if let firstResponder = subView.findFirstResponder() { 34 | return firstResponder 35 | } 36 | } 37 | return nil 38 | } 39 | 40 | public func formCell() -> BaseCell? { 41 | if self is UITableViewCell { 42 | return self as? BaseCell 43 | } 44 | return superview?.formCell() 45 | } 46 | } 47 | 48 | extension NSPredicate { 49 | 50 | var predicateVars: [String] { 51 | var ret = [String]() 52 | if let compoundPredicate = self as? NSCompoundPredicate { 53 | for subPredicate in compoundPredicate.subpredicates where subPredicate is NSPredicate { 54 | ret.append(contentsOf: (subPredicate as! NSPredicate).predicateVars) 55 | } 56 | } else if let comparisonPredicate = self as? NSComparisonPredicate { 57 | ret.append(contentsOf: comparisonPredicate.leftExpression.expressionVars) 58 | ret.append(contentsOf: comparisonPredicate.rightExpression.expressionVars) 59 | } 60 | return ret 61 | } 62 | } 63 | 64 | extension NSExpression { 65 | 66 | var expressionVars: [String] { 67 | switch expressionType { 68 | case .function, .variable: 69 | let str = "\(self)" 70 | if let range = str.range(of: ".") { 71 | return [String(str[str.index(str.startIndex, offsetBy: 1)..? { get set } 38 | 39 | /// Will be called before the presentation occurs. 40 | var onPresentCallback: ((FormViewController, PresentedControllerType) -> Void)? { get set } 41 | } 42 | 43 | extension PresenterRowType { 44 | 45 | /** 46 | Sets a block to be executed when the row presents a view controller 47 | 48 | - parameter callback: the block 49 | 50 | - returns: this row 51 | */ 52 | @discardableResult 53 | public func onPresent(_ callback: ((FormViewController, PresentedControllerType) -> Void)?) -> Self { 54 | onPresentCallback = callback 55 | return self 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Source/Core/ResultBuilders.swift: -------------------------------------------------------------------------------- 1 | // ResultBuilders.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2022 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #if swift(>=5.4) 26 | public protocol RowsProvider { 27 | var rows: [BaseRow] { get } 28 | } 29 | 30 | extension BaseRow: RowsProvider { 31 | public var rows: [BaseRow] { [self] } 32 | } 33 | 34 | extension Array: RowsProvider where Element == BaseRow { 35 | public var rows: [BaseRow] { self } 36 | } 37 | 38 | public protocol SectionsProvider { 39 | var sections: [Section] { get } 40 | } 41 | 42 | extension Section: SectionsProvider { 43 | public var sections: [Section] { [self] } 44 | } 45 | 46 | extension Array: SectionsProvider where Element == Section { 47 | public var sections: [Section] { self } 48 | } 49 | 50 | extension BaseRow: SectionsProvider { 51 | public var sections: [Section] { [.init([self])] } 52 | } 53 | 54 | @resultBuilder 55 | public struct SectionBuilder { 56 | public static func buildBlock(_ components: RowsProvider...) -> [BaseRow] { 57 | components.flatMap { $0.rows } 58 | } 59 | 60 | public static func buildFinalResult(_ components: [BaseRow]) -> Section { 61 | .init(components) 62 | } 63 | 64 | public static func buildEither(first components: [RowsProvider]) -> [BaseRow] { 65 | components.flatMap { $0.rows } 66 | } 67 | 68 | public static func buildEither(second components: [RowsProvider]) -> [BaseRow] { 69 | components.flatMap { $0.rows } 70 | } 71 | 72 | public static func buildOptional(_ components: [RowsProvider]?) -> [BaseRow] { 73 | components?.flatMap { $0.rows } ?? [] 74 | } 75 | 76 | public static func buildExpression(_ expression: RowsProvider?) -> [BaseRow] { 77 | expression.flatMap { $0.rows } ?? [] 78 | } 79 | } 80 | 81 | @resultBuilder 82 | public struct FormBuilder { 83 | public static func buildBlock(_ components: SectionsProvider...) -> [Section] { 84 | components.flatMap { $0.sections } 85 | } 86 | 87 | public static func buildFinalResult(_ components: [Section]) -> Form { 88 | .init(components) 89 | } 90 | 91 | public static func buildEither(first components: [SectionsProvider]) -> [Section] { 92 | components.flatMap { $0.sections } 93 | } 94 | 95 | public static func buildEither(second components: [SectionsProvider]) -> [Section] { 96 | components.flatMap { $0.sections } 97 | } 98 | 99 | public static func buildOptional(_ components: [SectionsProvider]?) -> [Section] { 100 | components?.flatMap { $0.sections } ?? [] 101 | } 102 | 103 | public static func buildExpression(_ expression: SectionsProvider?) -> [Section] { 104 | expression.flatMap { $0.sections } ?? [] 105 | } 106 | } 107 | #endif 108 | -------------------------------------------------------------------------------- /Source/Core/RowControllerType.swift: -------------------------------------------------------------------------------- 1 | // RowControllerType.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | /** 29 | * Base protocol for view controllers presented by Eureka rows. 30 | */ 31 | public protocol RowControllerType: NSObjectProtocol { 32 | 33 | /// A closure to be called when the controller disappears. 34 | var onDismissCallback: ((UIViewController) -> Void)? { get set } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Core/RowProtocols.swift: -------------------------------------------------------------------------------- 1 | // RowProtocols.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | /** 29 | * Protocol that view controllers pushed or presented by a row should conform to. 30 | */ 31 | public protocol TypedRowControllerType: RowControllerType { 32 | associatedtype RowValue: Equatable 33 | 34 | /// The row that pushed or presented this controller 35 | var row: RowOf! { get set } 36 | } 37 | 38 | // MARK: Header Footer Protocols 39 | 40 | /** 41 | * Protocol used to set headers and footers to sections. 42 | * Can be set with a view or a String 43 | */ 44 | public protocol HeaderFooterViewRepresentable { 45 | 46 | /** 47 | This method can be called to get the view corresponding to the header or footer of a section in a specific controller. 48 | 49 | - parameter section: The section from which to get the view. 50 | - parameter type: Either header or footer. 51 | - parameter controller: The controller from which to get that view. 52 | 53 | - returns: The header or footer of the specified section. 54 | */ 55 | func viewForSection(_ section: Section, type: HeaderFooterType) -> UIView? 56 | 57 | /// If the header or footer of a section was created with a String then it will be stored in the title. 58 | var title: String? { get set } 59 | 60 | /// The height of the header or footer. 61 | var height: (() -> CGFloat)? { get set } 62 | } 63 | -------------------------------------------------------------------------------- /Source/Core/SelectableRowType.swift: -------------------------------------------------------------------------------- 1 | // SelectableRowType.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | /** 28 | * Every row that shall be used in a SelectableSection must conform to this protocol. 29 | */ 30 | public protocol SelectableRowType: RowType { 31 | var selectableValue: Cell.Value? { get set } 32 | } 33 | -------------------------------------------------------------------------------- /Source/Core/Validation.swift: -------------------------------------------------------------------------------- 1 | // RowValidationType.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct ValidationError: Equatable { 28 | 29 | public let msg: String 30 | 31 | public init(msg: String) { 32 | self.msg = msg 33 | } 34 | } 35 | 36 | public func == (lhs: ValidationError, rhs: ValidationError) -> Bool { 37 | return lhs.msg == rhs.msg 38 | } 39 | 40 | public protocol BaseRuleType { 41 | var id: String? { get set } 42 | var validationError: ValidationError { get set } 43 | } 44 | 45 | public protocol RuleType: BaseRuleType { 46 | associatedtype RowValueType 47 | 48 | func isValid(value: RowValueType?) -> ValidationError? 49 | } 50 | 51 | public struct ValidationOptions: OptionSet { 52 | 53 | public let rawValue: Int 54 | 55 | public init(rawValue: Int) { 56 | self.rawValue = rawValue 57 | } 58 | 59 | public static let validatesOnDemand = ValidationOptions(rawValue: 1 << 0) 60 | public static let validatesOnChange = ValidationOptions(rawValue: 1 << 1) 61 | public static let validatesOnBlur = ValidationOptions(rawValue: 1 << 2) 62 | public static let validatesOnChangeAfterBlurred = ValidationOptions(rawValue: 1 << 3) 63 | 64 | public static let validatesAlways: ValidationOptions = [.validatesOnChange, .validatesOnBlur] 65 | } 66 | 67 | public struct ValidationRuleHelper where T: Equatable { 68 | let validateFn: ((T?) -> ValidationError?) 69 | public let rule: BaseRuleType 70 | } 71 | 72 | public struct RuleSet { 73 | 74 | internal var rules: [ValidationRuleHelper] = [] 75 | 76 | public init() {} 77 | 78 | /// Add a validation Rule to a Row 79 | /// - Parameter rule: RuleType object typed to the same type of the Row.value 80 | public mutating func add(rule: Rule) where T == Rule.RowValueType { 81 | let validFn: ((T?) -> ValidationError?) = { (val: T?) in 82 | return rule.isValid(value: val) 83 | } 84 | rules.append(ValidationRuleHelper(validateFn: validFn, rule: rule)) 85 | } 86 | 87 | public mutating func remove(ruleWithIdentifier identifier: String) { 88 | if let index = rules.firstIndex(where: { (validationRuleHelper) -> Bool in 89 | return validationRuleHelper.rule.id == identifier 90 | }) { 91 | rules.remove(at: index) 92 | } 93 | } 94 | 95 | public mutating func removeAllRules() { 96 | rules.removeAll() 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /Source/Eureka.h: -------------------------------------------------------------------------------- 1 | // Eureka.h 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | #import 26 | 27 | //! Project version number for Eureka. 28 | FOUNDATION_EXPORT double EurekaVersionNumber; 29 | 30 | //! Project version string for Eureka. 31 | FOUNDATION_EXPORT const unsigned char EurekaVersionString[]; 32 | 33 | // In this header, you should import all the public headers of your framework using statements like #import 34 | 35 | 36 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Source/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyCollectedDataTypes 6 | 7 | 8 | NSPrivacyCollectedDataType 9 | NSPrivacyCollectedDataTypeOtherUsageData 10 | NSPrivacyCollectedDataTypeLinked 11 | 12 | NSPrivacyCollectedDataTypeTracking 13 | 14 | NSPrivacyCollectedDataTypePurposes 15 | 16 | NSPrivacyCollectedDataTypePurposeAppFunctionality 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Source/Rows/ActionSheetRow.swift: -------------------------------------------------------------------------------- 1 | // ActionSheetRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class AlertSelectorCell : Cell, CellType where T: Equatable { 29 | 30 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 31 | super.init(style: style, reuseIdentifier: reuseIdentifier) 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | } 37 | 38 | open override func update() { 39 | super.update() 40 | accessoryType = .none 41 | editingAccessoryType = accessoryType 42 | selectionStyle = row.isDisabled ? .none : .default 43 | } 44 | 45 | open override func didSelect() { 46 | super.didSelect() 47 | row.deselect() 48 | } 49 | } 50 | 51 | open class _ActionSheetRow: AlertOptionsRow, PresenterRowType where Cell: BaseCell { 52 | 53 | public typealias ProviderType = SelectorAlertController<_ActionSheetRow> 54 | 55 | public var onPresentCallback: ((FormViewController, ProviderType) -> Void)? 56 | lazy public var presentationMode: PresentationMode? = { 57 | return .presentModally(controllerProvider: ControllerProvider.callback { [weak self] in 58 | let vc = SelectorAlertController<_ActionSheetRow>(title: self?.selectorTitle, message: nil, preferredStyle: .actionSheet) 59 | if let popView = vc.popoverPresentationController { 60 | guard let cell = self?.cell, let tableView = cell.formViewController()?.tableView else { fatalError() } 61 | popView.sourceView = tableView 62 | popView.sourceRect = tableView.convert(cell.detailTextLabel?.frame ?? cell.textLabel?.frame ?? cell.contentView.frame, from: cell) 63 | } 64 | vc.row = self 65 | return vc 66 | }, 67 | onDismiss: { [weak self] in 68 | $0.dismiss(animated: true) 69 | self?.cell?.formViewController()?.tableView?.reloadData() 70 | }) 71 | }() 72 | 73 | public required init(tag: String?) { 74 | super.init(tag: tag) 75 | } 76 | 77 | open override func customDidSelect() { 78 | super.customDidSelect() 79 | if let presentationMode = presentationMode, !isDisabled { 80 | if let controller = presentationMode.makeController() { 81 | controller.row = self 82 | onPresentCallback?(cell.formViewController()!, controller) 83 | presentationMode.present(controller, row: self, presentingController: cell.formViewController()!) 84 | } else { 85 | presentationMode.present(nil, row: self, presentingController: cell.formViewController()!) 86 | } 87 | } 88 | } 89 | } 90 | 91 | /// An options row where the user can select an option from an ActionSheet 92 | public final class ActionSheetRow: _ActionSheetRow>, RowType where T: Equatable { 93 | required public init(tag: String?) { 94 | super.init(tag: tag) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Source/Rows/AlertRow.swift: -------------------------------------------------------------------------------- 1 | // AlertRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | import Foundation 25 | import UIKit 26 | 27 | open class _AlertRow: AlertOptionsRow, PresenterRowType where Cell: BaseCell { 28 | 29 | public typealias PresentedController = SelectorAlertController<_AlertRow> 30 | 31 | open var onPresentCallback: ((FormViewController, PresentedController) -> Void)? 32 | lazy open var presentationMode: PresentationMode? = { 33 | return .presentModally(controllerProvider: ControllerProvider.callback { [weak self] in 34 | let vc = PresentedController(title: self?.selectorTitle, message: nil, preferredStyle: .alert) 35 | vc.row = self 36 | return vc 37 | }, onDismiss: { [weak self] in 38 | $0.dismiss(animated: true) 39 | self?.cell?.formViewController()?.tableView?.reloadData() 40 | }) 41 | }() 42 | 43 | public required init(tag: String?) { 44 | super.init(tag: tag) 45 | } 46 | 47 | open override func customDidSelect() { 48 | super.customDidSelect() 49 | if let presentationMode = presentationMode, !isDisabled { 50 | if let controller = presentationMode.makeController() { 51 | controller.row = self 52 | onPresentCallback?(cell.formViewController()!, controller) 53 | presentationMode.present(controller, row: self, presentingController: cell.formViewController()!) 54 | } else { 55 | presentationMode.present(nil, row: self, presentingController: cell.formViewController()!) 56 | } 57 | } 58 | } 59 | } 60 | 61 | /// An options row where the user can select an option from a modal Alert 62 | public final class AlertRow: _AlertRow>, RowType { 63 | required public init(tag: String?) { 64 | super.init(tag: tag) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Source/Rows/ButtonRowWithPresent.swift: -------------------------------------------------------------------------------- 1 | // Rows.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class _ButtonRowWithPresent: Row>, PresenterRowType where VCType: UIViewController { 29 | 30 | open var presentationMode: PresentationMode? 31 | open var onPresentCallback: ((FormViewController, VCType) -> Void)? 32 | 33 | required public init(tag: String?) { 34 | super.init(tag: tag) 35 | displayValueFor = nil 36 | cellStyle = .default 37 | } 38 | 39 | open override func customUpdateCell() { 40 | super.customUpdateCell() 41 | let leftAligmnment = presentationMode != nil 42 | cell.textLabel?.textAlignment = leftAligmnment ? .left : .center 43 | cell.accessoryType = !leftAligmnment || isDisabled ? .none : .disclosureIndicator 44 | cell.editingAccessoryType = cell.accessoryType 45 | if !leftAligmnment { 46 | var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 47 | cell.tintColor.getRed(&red, green: &green, blue: &blue, alpha: &alpha) 48 | cell.textLabel?.textColor = UIColor(red: red, green: green, blue: blue, alpha:isDisabled ? 0.3 : 1.0) 49 | } else { 50 | cell.textLabel?.textColor = nil 51 | } 52 | } 53 | 54 | open override func customDidSelect() { 55 | super.customDidSelect() 56 | if let presentationMode = presentationMode, !isDisabled { 57 | if let controller = presentationMode.makeController() { 58 | controller.row = self 59 | onPresentCallback?(cell.formViewController()!, controller) 60 | presentationMode.present(controller, row: self, presentingController: cell.formViewController()!) 61 | } else { 62 | presentationMode.present(nil, row: self, presentingController: cell.formViewController()!) 63 | } 64 | } 65 | } 66 | 67 | open override func prepare(for segue: UIStoryboardSegue) { 68 | super.prepare(for: segue) 69 | guard let rowVC = segue.destination as? VCType else { 70 | return 71 | } 72 | if let callback = presentationMode?.onDismissCallback { 73 | rowVC.onDismissCallback = callback 74 | } 75 | rowVC.row = self 76 | onPresentCallback?(cell.formViewController()!, rowVC) 77 | } 78 | 79 | } 80 | 81 | // MARK: Rows 82 | 83 | /// A generic row with a button that presents a view controller when tapped 84 | public final class ButtonRowWithPresent : _ButtonRowWithPresent, RowType where VCType: UIViewController { 85 | public required init(tag: String?) { 86 | super.init(tag: tag) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Source/Rows/CheckRow.swift: -------------------------------------------------------------------------------- 1 | // CheckRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | // MARK: CheckCell 29 | 30 | open class CheckCell: Cell, CellType { 31 | 32 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 33 | super.init(style: style, reuseIdentifier: reuseIdentifier) 34 | } 35 | 36 | required public init?(coder aDecoder: NSCoder) { 37 | super.init(coder: aDecoder) 38 | } 39 | 40 | open override func update() { 41 | super.update() 42 | accessoryType = row.value == true ? .checkmark : .none 43 | editingAccessoryType = accessoryType 44 | selectionStyle = .default 45 | if row.isDisabled { 46 | tintAdjustmentMode = .dimmed 47 | selectionStyle = .none 48 | } else { 49 | tintAdjustmentMode = .automatic 50 | } 51 | } 52 | 53 | open override func setup() { 54 | super.setup() 55 | accessoryType = .checkmark 56 | editingAccessoryType = accessoryType 57 | } 58 | 59 | open override func didSelect() { 60 | row.value = row.value ?? false ? false : true 61 | row.deselect() 62 | row.updateCell() 63 | } 64 | 65 | } 66 | 67 | // MARK: CheckRow 68 | 69 | open class _CheckRow: Row { 70 | 71 | required public init(tag: String?) { 72 | super.init(tag: tag) 73 | displayValueFor = nil 74 | } 75 | } 76 | 77 | ///// Boolean row that has a checkmark as accessoryType 78 | public final class CheckRow: _CheckRow, RowType { 79 | 80 | required public init(tag: String?) { 81 | super.init(tag: tag) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Source/Rows/Common/AlertOptionsRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AlertOptionsRow.swift 3 | // Eureka ( https://github.com/xmartlabs/Eureka ) 4 | // 5 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 6 | // 7 | // 8 | // Permission is hereby granted, free of charge, to any person obtaining a copy 9 | // of this software and associated documentation files (the "Software"), to deal 10 | // in the Software without restriction, including without limitation the rights 11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | // copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in 16 | // all copies or substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | // THE SOFTWARE. 25 | 26 | import Foundation 27 | 28 | 29 | import Foundation 30 | 31 | open class AlertOptionsRow : OptionsRow, AlertOptionsProviderRow where Cell: BaseCell { 32 | 33 | typealias OptionsProviderType = OptionsProvider 34 | 35 | open var cancelTitle: String? 36 | 37 | required public init(tag: String?) { 38 | super.init(tag: tag) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Source/Rows/Common/DateInlineFieldRow.swift: -------------------------------------------------------------------------------- 1 | // DateInlineFieldRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class DateInlineCell: Cell, CellType { 29 | 30 | public required init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 31 | super.init(style: style, reuseIdentifier: reuseIdentifier) 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | } 37 | 38 | open override func setup() { 39 | super.setup() 40 | accessoryType = .none 41 | editingAccessoryType = .none 42 | } 43 | 44 | open override func update() { 45 | super.update() 46 | selectionStyle = row.isDisabled ? .none : .default 47 | } 48 | 49 | open override func didSelect() { 50 | super.didSelect() 51 | row.deselect() 52 | } 53 | } 54 | 55 | open class _DateInlineFieldRow: Row, DatePickerRowProtocol, NoValueDisplayTextConformance { 56 | 57 | /// The minimum value for this row's UIDatePicker 58 | open var minimumDate: Date? 59 | 60 | /// The maximum value for this row's UIDatePicker 61 | open var maximumDate: Date? 62 | 63 | /// The interval between options for this row's UIDatePicker 64 | open var minuteInterval: Int? 65 | 66 | /// The formatter for the date picked by the user 67 | open var dateFormatter: DateFormatter? 68 | 69 | open var noValueDisplayText: String? 70 | 71 | required public init(tag: String?) { 72 | super.init(tag: tag) 73 | dateFormatter = DateFormatter() 74 | dateFormatter?.locale = Locale.current 75 | displayValueFor = { [unowned self] value in 76 | guard let val = value, let formatter = self.dateFormatter else { return nil } 77 | return formatter.string(from: val) 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Source/Rows/Common/DecimalFormatter.swift: -------------------------------------------------------------------------------- 1 | // DecimalFormatter.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | /// A custom formatter for numbers with two digits after the decimal mark 29 | open class DecimalFormatter: NumberFormatter, FormatterProtocol { 30 | 31 | /// Creates the formatter with 2 Fraction Digits, Locale set to .current and .decimal NumberFormatter.Style 32 | public override init() { 33 | super.init() 34 | locale = Locale.current 35 | numberStyle = .decimal 36 | minimumFractionDigits = 2 37 | maximumFractionDigits = 2 38 | } 39 | 40 | required public init?(coder aDecoder: NSCoder) { 41 | fatalError("init(coder:) has not been implemented") 42 | } 43 | 44 | /// Creates an NSNumber from the given String 45 | /// - Parameter obj: Pointer to NSNumber object to assign 46 | /// - Parameter string: String with number assumed to have the configured min. fraction digits. 47 | /// - Parameter rangep: Unused range parameter 48 | override open func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer?, for string: String, range rangep: UnsafeMutablePointer?) throws { 49 | guard obj != nil else { return } 50 | let str = string.components(separatedBy: CharacterSet.decimalDigits.inverted).joined(separator: "") 51 | // Recover the number from the string in a way that forces the formatter's fraction digits 52 | // numberWithoutDecimals / 10 ^ minimumFractionDigits 53 | obj?.pointee = NSNumber(value: (Double(str) ?? 0.0)/Double(pow(10.0, Double(minimumFractionDigits)))) 54 | } 55 | 56 | open func getNewPosition(forPosition position: UITextPosition, inTextInput textInput: UITextInput, oldValue: String?, newValue: String?) -> UITextPosition { 57 | return textInput.position(from: position, offset:((newValue?.count ?? 0) - (oldValue?.count ?? 0))) ?? position 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Source/Rows/Common/GenericMultipleSelectorRow.swift: -------------------------------------------------------------------------------- 1 | // GenericMultipleSelectorRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | /// Generic options selector row that allows multiple selection. 29 | open class GenericMultipleSelectorRow: Row, PresenterRowType, NoValueDisplayTextConformance, OptionsProviderRow 30 | where Cell: BaseCell, Cell.Value == Set { 31 | 32 | public typealias PresentedController = MultipleSelectorViewController> 33 | 34 | /// Defines how the view controller will be presented, pushed, etc. 35 | open var presentationMode: PresentationMode? 36 | 37 | /// Will be called before the presentation occurs. 38 | open var onPresentCallback: ((FormViewController, PresentedController) -> Void)? 39 | 40 | /// Title to be displayed for the options 41 | open var selectorTitle: String? 42 | open var noValueDisplayText: String? 43 | 44 | /// Options from which the user will choose 45 | open var optionsProvider: OptionsProvider? 46 | 47 | required public init(tag: String?) { 48 | super.init(tag: tag) 49 | displayValueFor = { (rowValue: Set?) in 50 | return rowValue?.map({ String(describing: $0) }).sorted().joined(separator: ", ") 51 | } 52 | presentationMode = .show(controllerProvider: ControllerProvider.callback { 53 | return MultipleSelectorViewController>() 54 | }, onDismiss: { vc in 55 | let _ = vc.navigationController?.popViewController(animated: true) 56 | }) 57 | } 58 | 59 | /** 60 | Extends `didSelect` method 61 | */ 62 | open override func customDidSelect() { 63 | super.customDidSelect() 64 | guard let presentationMode = presentationMode, !isDisabled else { return } 65 | if let controller = presentationMode.makeController() { 66 | controller.row = self 67 | controller.title = selectorTitle ?? controller.title 68 | onPresentCallback?(cell.formViewController()!, controller) 69 | presentationMode.present(controller, row: self, presentingController: self.cell.formViewController()!) 70 | } else { 71 | presentationMode.present(nil, row: self, presentingController: self.cell.formViewController()!) 72 | } 73 | } 74 | 75 | /** 76 | Prepares the pushed row setting its title and completion callback. 77 | */ 78 | open override func prepare(for segue: UIStoryboardSegue) { 79 | super.prepare(for: segue) 80 | guard let rowVC = segue.destination as Any as? PresentedController else { return } 81 | rowVC.title = selectorTitle ?? rowVC.title 82 | rowVC.onDismissCallback = presentationMode?.onDismissCallback ?? rowVC.onDismissCallback 83 | onPresentCallback?(cell.formViewController()!, rowVC) 84 | rowVC.row = self 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Source/Rows/Common/OptionsRow.swift: -------------------------------------------------------------------------------- 1 | // OptionsRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | open class OptionsRow : Row, NoValueDisplayTextConformance, OptionsProviderRow where Cell: BaseCell { 28 | 29 | open var optionsProvider: OptionsProvider? 30 | 31 | open var selectorTitle: String? 32 | open var noValueDisplayText: String? 33 | 34 | required public init(tag: String?) { 35 | super.init(tag: tag) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Source/Rows/Common/Protocols.swift: -------------------------------------------------------------------------------- 1 | // Protocols.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public protocol FormatterConformance: AnyObject { 28 | var formatter: Formatter? { get set } 29 | var useFormatterDuringInput: Bool { get set } 30 | var useFormatterOnDidBeginEditing: Bool? { get set } 31 | } 32 | 33 | public protocol NoValueDisplayTextConformance: AnyObject { 34 | var noValueDisplayText: String? { get set } 35 | } 36 | -------------------------------------------------------------------------------- /Source/Rows/Common/SelectorRow.swift: -------------------------------------------------------------------------------- 1 | // SelectorRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class PushSelectorCell : Cell, CellType { 29 | 30 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 31 | super.init(style: style, reuseIdentifier: reuseIdentifier) 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | } 37 | 38 | open override func update() { 39 | super.update() 40 | accessoryType = .disclosureIndicator 41 | editingAccessoryType = accessoryType 42 | selectionStyle = row.isDisabled ? .none : .default 43 | } 44 | } 45 | 46 | /// Generic row type where a user must select a value among several options. 47 | open class SelectorRow: OptionsRow, PresenterRowType where Cell: BaseCell { 48 | 49 | 50 | /// Defines how the view controller will be presented, pushed, etc. 51 | open var presentationMode: PresentationMode>>? 52 | 53 | /// Will be called before the presentation occurs. 54 | open var onPresentCallback: ((FormViewController, SelectorViewController>) -> Void)? 55 | 56 | required public init(tag: String?) { 57 | super.init(tag: tag) 58 | } 59 | 60 | /** 61 | Extends `didSelect` method 62 | */ 63 | open override func customDidSelect() { 64 | super.customDidSelect() 65 | guard let presentationMode = presentationMode, !isDisabled else { return } 66 | if let controller = presentationMode.makeController() { 67 | controller.row = self 68 | controller.title = selectorTitle ?? controller.title 69 | onPresentCallback?(cell.formViewController()!, controller) 70 | presentationMode.present(controller, row: self, presentingController: self.cell.formViewController()!) 71 | } else { 72 | presentationMode.present(nil, row: self, presentingController: self.cell.formViewController()!) 73 | } 74 | } 75 | 76 | /** 77 | Prepares the pushed row setting its title and completion callback. 78 | */ 79 | open override func prepare(for segue: UIStoryboardSegue) { 80 | super.prepare(for: segue) 81 | guard let rowVC = segue.destination as Any as? SelectorViewController> else { return } 82 | rowVC.title = selectorTitle ?? rowVC.title 83 | rowVC.onDismissCallback = presentationMode?.onDismissCallback ?? rowVC.onDismissCallback 84 | onPresentCallback?(cell.formViewController()!, rowVC) 85 | rowVC.row = self 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Source/Rows/Controllers/SelectorAlertController.swift: -------------------------------------------------------------------------------- 1 | // SelectorAlertController.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | /// Specific type, Responsible for the options passed to a selector alert view controller 29 | public protocol AlertOptionsProviderRow: OptionsProviderRow { 30 | 31 | var cancelTitle: String? { get set } 32 | 33 | } 34 | 35 | /// Selector UIAlertController 36 | open class SelectorAlertController: UIAlertController, TypedRowControllerType where AlertOptionsRow.OptionsProviderType.Option == AlertOptionsRow.Cell.Value, AlertOptionsRow: BaseRow { 37 | 38 | /// The row that pushed or presented this controller 39 | public var row: RowOf! 40 | 41 | @available(*, deprecated, message: "Use AlertOptionsRow.cancelTitle instead.") 42 | public var cancelTitle = NSLocalizedString("Cancel", comment: "") 43 | 44 | /// A closure to be called when the controller disappears. 45 | public var onDismissCallback: ((UIViewController) -> Void)? 46 | 47 | /// Options provider to use to get available options. 48 | /// If not set will use synchronous data provider built with `row.dataProvider.arrayData`. 49 | // public var optionsProvider: OptionsProvider? 50 | public var optionsProviderRow: AlertOptionsRow { 51 | return row as Any as! AlertOptionsRow 52 | } 53 | 54 | override public init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 55 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) 56 | } 57 | 58 | required public init?(coder aDecoder: NSCoder) { 59 | super.init(coder: aDecoder) 60 | } 61 | 62 | convenience public init(_ callback: ((UIViewController) -> Void)?) { 63 | self.init() 64 | onDismissCallback = callback 65 | } 66 | 67 | open override func viewDidLoad() { 68 | super.viewDidLoad() 69 | guard let options = optionsProviderRow.options else { return } 70 | let cancelTitle = optionsProviderRow.cancelTitle ?? NSLocalizedString("Cancel", comment: "") 71 | addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: nil)) 72 | for option in options { 73 | addAction(UIAlertAction(title: row.displayValueFor?(option), style: .default, handler: { [weak self] _ in 74 | self?.row.value = option 75 | self?.onDismissCallback?(self!) 76 | })) 77 | } 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Source/Rows/DateRow.swift: -------------------------------------------------------------------------------- 1 | // DateRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | import Foundation 25 | 26 | open class _DateRow: _DateFieldRow { 27 | required public init(tag: String?) { 28 | super.init(tag: tag) 29 | dateFormatter = DateFormatter() 30 | dateFormatter?.timeStyle = .none 31 | dateFormatter?.dateStyle = .medium 32 | dateFormatter?.locale = Locale.current 33 | } 34 | } 35 | 36 | open class _TimeRow: _DateFieldRow { 37 | required public init(tag: String?) { 38 | super.init(tag: tag) 39 | dateFormatter = DateFormatter() 40 | dateFormatter?.timeStyle = .short 41 | dateFormatter?.dateStyle = .none 42 | dateFormatter?.locale = Locale.current 43 | } 44 | } 45 | 46 | open class _DateTimeRow: _DateFieldRow { 47 | required public init(tag: String?) { 48 | super.init(tag: tag) 49 | dateFormatter = DateFormatter() 50 | dateFormatter?.timeStyle = .short 51 | dateFormatter?.dateStyle = .short 52 | dateFormatter?.locale = Locale.current 53 | } 54 | } 55 | 56 | open class _CountDownRow: _DateFieldRow { 57 | required public init(tag: String?) { 58 | super.init(tag: tag) 59 | displayValueFor = { [unowned self] value in 60 | guard let val = value else { 61 | return nil 62 | } 63 | if let formatter = self.dateFormatter { 64 | return formatter.string(from: val) 65 | } 66 | 67 | let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: val) 68 | return DateComponentsFormatter.localizedString(from: dateComponents, unitsStyle: .full)?.replacingOccurrences(of: ",", with: "") 69 | } 70 | } 71 | } 72 | 73 | /// A row with an Date as value where the user can select a date from a picker view. 74 | public final class DateRow: _DateRow, RowType { 75 | required public init(tag: String?) { 76 | super.init(tag: tag) 77 | } 78 | } 79 | 80 | /// A row with an Date as value where the user can select a time from a picker view. 81 | public final class TimeRow: _TimeRow, RowType { 82 | required public init(tag: String?) { 83 | super.init(tag: tag) 84 | } 85 | } 86 | 87 | /// A row with an Date as value where the user can select date and time from a picker view. 88 | public final class DateTimeRow: _DateTimeRow, RowType { 89 | required public init(tag: String?) { 90 | super.init(tag: tag) 91 | } 92 | } 93 | 94 | /// A row with an Date as value where the user can select hour and minute as a countdown timer in a picker view. 95 | public final class CountDownRow: _CountDownRow, RowType { 96 | required public init(tag: String?) { 97 | super.init(tag: tag) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Source/Rows/LabelRow.swift: -------------------------------------------------------------------------------- 1 | // LabelRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | // MARK: LabelCell 29 | 30 | open class LabelCellOf: Cell, CellType { 31 | 32 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 33 | super.init(style: style, reuseIdentifier: reuseIdentifier) 34 | } 35 | 36 | required public init?(coder aDecoder: NSCoder) { 37 | super.init(coder: aDecoder) 38 | } 39 | 40 | open override func setup() { 41 | super.setup() 42 | selectionStyle = .none 43 | } 44 | } 45 | 46 | public typealias LabelCell = LabelCellOf 47 | 48 | // MARK: LabelRow 49 | 50 | open class _LabelRow: Row { 51 | required public init(tag: String?) { 52 | super.init(tag: tag) 53 | } 54 | } 55 | 56 | /// Simple row that can show title and value but is not editable by user. 57 | public final class LabelRow: _LabelRow, RowType { 58 | required public init(tag: String?) { 59 | super.init(tag: tag) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/Rows/MultipleSelectorRow.swift: -------------------------------------------------------------------------------- 1 | // MultipleSelectorRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | open class _MultipleSelectorRow: GenericMultipleSelectorRow where Cell: BaseCell, Cell.Value == Set { 28 | public required init(tag: String?) { 29 | super.init(tag: tag) 30 | } 31 | } 32 | 33 | /// A selector row where the user can pick several options from a pushed view controller 34 | public final class MultipleSelectorRow : _MultipleSelectorRow>>, RowType { 35 | public required init(tag: String?) { 36 | super.init(tag: tag) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Rows/PopoverSelectorRow.swift: -------------------------------------------------------------------------------- 1 | // PopoverSelectorRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class _PopoverSelectorRow : SelectorRow where Cell: BaseCell { 29 | 30 | public required init(tag: String?) { 31 | super.init(tag: tag) 32 | onPresentCallback = { [weak self] (_, viewController) -> Void in 33 | guard let porpoverController = viewController.popoverPresentationController, let tableView = self?.baseCell.formViewController()?.tableView, let cell = self?.cell else { 34 | fatalError() 35 | } 36 | porpoverController.sourceView = tableView 37 | porpoverController.sourceRect = tableView.convert(cell.detailTextLabel?.frame ?? cell.textLabel?.frame ?? cell.contentView.frame, from: cell) 38 | } 39 | presentationMode = .popover(controllerProvider: ControllerProvider.callback { return SelectorViewController> { _ in } }, onDismiss: { [weak self] in 40 | $0.dismiss(animated: true) 41 | self?.reload() 42 | }) 43 | } 44 | 45 | open override func didSelect() { 46 | deselect() 47 | super.didSelect() 48 | } 49 | } 50 | 51 | public final class PopoverSelectorRow : _PopoverSelectorRow>, RowType { 52 | public required init(tag: String?) { 53 | super.init(tag: tag) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Rows/PushRow.swift: -------------------------------------------------------------------------------- 1 | // PushRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class _PushRow: SelectorRow where Cell: BaseCell { 29 | 30 | public required init(tag: String?) { 31 | super.init(tag: tag) 32 | presentationMode = .show(controllerProvider: ControllerProvider.callback { return SelectorViewController> { _ in } }, onDismiss: { vc in 33 | let _ = vc.navigationController?.popViewController(animated: true) }) 34 | } 35 | } 36 | 37 | /// A selector row where the user can pick an option from a pushed view controller 38 | public final class PushRow : _PushRow>, RowType { 39 | public required init(tag: String?) { 40 | super.init(tag: tag) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Source/Rows/SelectableRows/ListCheckRow.swift: -------------------------------------------------------------------------------- 1 | // ListCheckRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | open class ListCheckCell : Cell, CellType { 29 | 30 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 31 | super.init(style: style, reuseIdentifier: reuseIdentifier) 32 | } 33 | 34 | required public init?(coder aDecoder: NSCoder) { 35 | super.init(coder: aDecoder) 36 | } 37 | 38 | open override func update() { 39 | super.update() 40 | accessoryType = row.value != nil ? .checkmark : .none 41 | editingAccessoryType = accessoryType 42 | selectionStyle = .default 43 | if row.isDisabled { 44 | tintAdjustmentMode = .dimmed 45 | selectionStyle = .none 46 | } else { 47 | tintAdjustmentMode = .automatic 48 | } 49 | } 50 | 51 | open override func setup() { 52 | super.setup() 53 | accessoryType = .checkmark 54 | editingAccessoryType = accessoryType 55 | } 56 | 57 | open override func didSelect() { 58 | row.deselect() 59 | row.updateCell() 60 | } 61 | 62 | } 63 | 64 | public final class ListCheckRow: Row>, SelectableRowType, RowType where T: Equatable { 65 | public var selectableValue: T? 66 | required public init(tag: String?) { 67 | super.init(tag: tag) 68 | displayValueFor = nil 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Source/Rows/SwitchRow.swift: -------------------------------------------------------------------------------- 1 | // SwitchRow.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | // MARK: SwitchCell 29 | 30 | open class SwitchCell: Cell, CellType { 31 | 32 | @IBOutlet public weak var switchControl: UISwitch! 33 | 34 | required public init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { 35 | super.init(style: style, reuseIdentifier: reuseIdentifier) 36 | let switchC = UISwitch() 37 | switchControl = switchC 38 | accessoryView = switchControl 39 | editingAccessoryView = accessoryView 40 | } 41 | 42 | required public init?(coder aDecoder: NSCoder) { 43 | super.init(coder: aDecoder) 44 | } 45 | 46 | open override func setup() { 47 | super.setup() 48 | selectionStyle = .none 49 | switchControl.addTarget(self, action: #selector(SwitchCell.valueChanged), for: .valueChanged) 50 | } 51 | 52 | deinit { 53 | switchControl?.removeTarget(self, action: nil, for: .allEvents) 54 | } 55 | 56 | open override func update() { 57 | super.update() 58 | switchControl.isOn = row.value ?? false 59 | switchControl.isEnabled = !row.isDisabled 60 | } 61 | 62 | @objc (switchValueDidChange) func valueChanged() { 63 | row.value = switchControl?.isOn ?? false 64 | } 65 | } 66 | 67 | // MARK: SwitchRow 68 | 69 | open class _SwitchRow: Row { 70 | required public init(tag: String?) { 71 | super.init(tag: tag) 72 | displayValueFor = nil 73 | } 74 | } 75 | 76 | /// Boolean row that has a UISwitch as accessoryType 77 | public final class SwitchRow: _SwitchRow, RowType { 78 | required public init(tag: String?) { 79 | super.init(tag: tag) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Source/Validations/RuleClosure.swift: -------------------------------------------------------------------------------- 1 | // RuleClosure.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct RuleClosure: RuleType { 28 | 29 | public var id: String? 30 | public var validationError: ValidationError 31 | 32 | public var closure: (T?) -> ValidationError? 33 | 34 | public func isValid(value: T?) -> ValidationError? { 35 | return closure(value) 36 | } 37 | 38 | public init(validationError: ValidationError = ValidationError(msg: "Field validation fails.."), id: String? = nil, closure: @escaping ((T?) -> ValidationError?)) { 39 | self.validationError = validationError 40 | self.closure = closure 41 | self.id = id 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Validations/RuleEmail.swift: -------------------------------------------------------------------------------- 1 | // RuleEmail.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public class RuleEmail: RuleRegExp { 28 | 29 | public init(msg: String = "Field value should be a valid email!", id: String? = nil) { 30 | super.init(regExpr: RegExprPattern.EmailAddress.rawValue, allowsEmpty: true, msg: msg, id: id) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Source/Validations/RuleEqualsToRow.swift: -------------------------------------------------------------------------------- 1 | // RuleRequire.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct RuleEqualsToRow: RuleType { 28 | 29 | public init(form: Form, tag: String, msg: String = "Fields don't match!", id: String? = nil) { 30 | self.validationError = ValidationError(msg: msg) 31 | self.form = form 32 | self.tag = tag 33 | self.row = nil 34 | self.id = id 35 | } 36 | 37 | public init(row: RowOf, msg: String = "Fields don't match!", id: String? = nil) { 38 | self.validationError = ValidationError(msg: msg) 39 | self.form = nil 40 | self.tag = nil 41 | self.row = row 42 | self.id = id 43 | } 44 | 45 | public var id: String? 46 | public var validationError: ValidationError 47 | public weak var form: Form? 48 | public var tag: String? 49 | public weak var row: RowOf? 50 | 51 | public func isValid(value: T?) -> ValidationError? { 52 | let rowAux: RowOf = row ?? form!.rowBy(tag: tag!)! 53 | return rowAux.value == value ? nil : validationError 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Source/Validations/RuleLength.swift: -------------------------------------------------------------------------------- 1 | // RuleLength.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct RuleMinLength: RuleType { 28 | 29 | let min: UInt 30 | 31 | public var id: String? 32 | public var validationError: ValidationError 33 | 34 | public init(minLength: UInt, msg: String? = nil, id: String? = nil) { 35 | let ruleMsg = msg ?? "Field value must have at least \(minLength) characters" 36 | min = minLength 37 | validationError = ValidationError(msg: ruleMsg) 38 | self.id = id 39 | } 40 | 41 | public func isValid(value: String?) -> ValidationError? { 42 | guard let value = value, !value.isEmpty else { return nil } 43 | return value.count < Int(min) ? validationError : nil 44 | } 45 | } 46 | 47 | public struct RuleMaxLength: RuleType { 48 | 49 | let max: UInt 50 | 51 | public var id: String? 52 | public var validationError: ValidationError 53 | 54 | public init(maxLength: UInt, msg: String? = nil, id: String? = nil) { 55 | let ruleMsg = msg ?? "Field value must have less than \(maxLength) characters" 56 | max = maxLength 57 | validationError = ValidationError(msg: ruleMsg) 58 | self.id = id 59 | } 60 | 61 | public func isValid(value: String?) -> ValidationError? { 62 | guard let value = value, !value.isEmpty else { return nil } 63 | return value.count > Int(max) ? validationError : nil 64 | } 65 | } 66 | 67 | public struct RuleExactLength: RuleType { 68 | let length: UInt 69 | 70 | public var id: String? 71 | public var validationError: ValidationError 72 | 73 | public init(exactLength: UInt, msg: String? = nil, id: String? = nil) { 74 | let ruleMsg = msg ?? "Field value must have exactly \(exactLength) characters" 75 | length = exactLength 76 | validationError = ValidationError(msg: ruleMsg) 77 | self.id = id 78 | } 79 | 80 | public func isValid(value: String?) -> ValidationError? { 81 | guard let value = value, !value.isEmpty else { return nil } 82 | return value.count != Int(length) ? validationError : nil 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Source/Validations/RuleRange.swift: -------------------------------------------------------------------------------- 1 | // RuleRange.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct RuleGreaterThan: RuleType { 28 | 29 | let min: T 30 | 31 | public var id: String? 32 | public var validationError: ValidationError 33 | 34 | public init(min: T, msg: String? = nil, id: String? = nil) { 35 | let ruleMsg = msg ?? "Field value must be greater than \(min)" 36 | self.min = min 37 | self.validationError = ValidationError(msg: ruleMsg) 38 | self.id = id 39 | } 40 | 41 | public func isValid(value: T?) -> ValidationError? { 42 | guard let val = value else { return nil } 43 | guard val > min else { return validationError } 44 | return nil 45 | } 46 | } 47 | 48 | public struct RuleGreaterOrEqualThan: RuleType { 49 | 50 | let min: T 51 | 52 | public var id: String? 53 | public var validationError: ValidationError 54 | 55 | public init(min: T, msg: String? = nil, id: String? = nil) { 56 | let ruleMsg = msg ?? "Field value must be greater or equals than \(min)" 57 | self.min = min 58 | self.validationError = ValidationError(msg: ruleMsg) 59 | self.id = id 60 | } 61 | 62 | public func isValid(value: T?) -> ValidationError? { 63 | guard let val = value else { return nil } 64 | guard val >= min else { return validationError } 65 | return nil 66 | } 67 | } 68 | 69 | public struct RuleSmallerThan: RuleType { 70 | 71 | let max: T 72 | 73 | public var id: String? 74 | public var validationError: ValidationError 75 | 76 | public init(max: T, msg: String? = nil, id: String? = nil) { 77 | let ruleMsg = msg ?? "Field value must be smaller than \(max)" 78 | self.max = max 79 | self.validationError = ValidationError(msg: ruleMsg) 80 | self.id = id 81 | } 82 | 83 | public func isValid(value: T?) -> ValidationError? { 84 | guard let val = value else { return nil } 85 | guard val < max else { return validationError } 86 | return nil 87 | } 88 | } 89 | 90 | public struct RuleSmallerOrEqualThan: RuleType { 91 | 92 | let max: T 93 | 94 | public var id: String? 95 | public var validationError: ValidationError 96 | 97 | public init(max: T, msg: String? = nil, id: String? = nil) { 98 | let ruleMsg = msg ?? "Field value must be smaller or equals than \(max)" 99 | self.max = max 100 | self.validationError = ValidationError(msg: ruleMsg) 101 | self.id = id 102 | } 103 | 104 | public func isValid(value: T?) -> ValidationError? { 105 | guard let val = value else { return nil } 106 | guard val <= max else { return validationError } 107 | return nil 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Source/Validations/RuleRegExp.swift: -------------------------------------------------------------------------------- 1 | // RegexRule.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public enum RegExprPattern: String { 28 | case EmailAddress = "^[_A-Za-z0-9-+!?#$%'`*/=~^{}|]+(\\.[_A-Za-z0-9-+!?#$%'`*/=~^{}|]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z‌​]{2,})$" 29 | case URL = "^(?:(?:http|https)://)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$" 30 | case ContainsNumber = ".*\\d.*" 31 | case ContainsCapital = "^.*?[A-Z].*?$" 32 | case ContainsLowercase = "^.*?[a-z].*?$" 33 | } 34 | 35 | open class RuleRegExp: RuleType { 36 | 37 | public var regExpr: String = "" 38 | public var id: String? 39 | public var validationError: ValidationError 40 | public var allowsEmpty = true 41 | 42 | public init(regExpr: String, allowsEmpty: Bool = true, msg: String = "Invalid field value!", id: String? = nil) { 43 | self.validationError = ValidationError(msg: msg) 44 | self.regExpr = regExpr 45 | self.allowsEmpty = allowsEmpty 46 | self.id = id 47 | } 48 | 49 | public func isValid(value: String?) -> ValidationError? { 50 | if let value = value, !value.isEmpty { 51 | let predicate = NSPredicate(format: "SELF MATCHES %@", regExpr) 52 | guard predicate.evaluate(with: value) else { 53 | return validationError 54 | } 55 | return nil 56 | } else if !allowsEmpty { 57 | return validationError 58 | } 59 | return nil 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Source/Validations/RuleRequired.swift: -------------------------------------------------------------------------------- 1 | // RuleRequire.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | 27 | public struct RuleRequired: RuleType { 28 | 29 | public init(msg: String = "Field required!", id: String? = nil) { 30 | self.validationError = ValidationError(msg: msg) 31 | self.id = id 32 | } 33 | 34 | public var id: String? 35 | public var validationError: ValidationError 36 | 37 | public func isValid(value: T?) -> ValidationError? { 38 | if let str = value as? String { 39 | return str.isEmpty ? validationError : nil 40 | } 41 | return value != nil ? nil : validationError 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Source/Validations/RuleURL.swift: -------------------------------------------------------------------------------- 1 | // RuleURL.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs SRL ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import Foundation 26 | import UIKit 27 | 28 | public struct RuleURL: RuleType { 29 | 30 | public init(allowsEmpty: Bool = true, requiresProtocol: Bool = false, msg: String = "Field value must be an URL!", id: String? = nil) { 31 | validationError = ValidationError(msg: msg) 32 | self.allowsEmpty = allowsEmpty 33 | self.requiresProtocol = requiresProtocol 34 | self.id = id 35 | } 36 | 37 | public var id: String? 38 | public var allowsEmpty = true 39 | public var requiresProtocol = false 40 | public var validationError: ValidationError 41 | 42 | public func isValid(value: URL?) -> ValidationError? { 43 | if let value = value, value.absoluteString.isEmpty == false { 44 | let predicate = NSPredicate(format:"SELF MATCHES %@", RegExprPattern.URL.rawValue) 45 | guard predicate.evaluate(with: value.absoluteString) else { 46 | return validationError 47 | } 48 | return nil 49 | } else if !allowsEmpty { 50 | return validationError 51 | } 52 | return nil 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Tests/DateTests.swift: -------------------------------------------------------------------------------- 1 | // DateTests.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import XCTest 26 | @testable import Eureka 27 | 28 | class DateTests: BaseEurekaTests { 29 | 30 | override func setUp() { 31 | super.setUp() 32 | formVC.form = dateForm 33 | } 34 | 35 | func testMinMax() { 36 | 37 | let minRow: DateRow! = formVC.form.rowBy(tag: "MinDateRow_d1") 38 | let maxRow: DateRow! = formVC.form.rowBy(tag: "MaxDateRow_d1") 39 | let minMaxRow: DateRow! = formVC.form.rowBy(tag: "MinMaxDateRow_d1") 40 | 41 | XCTAssertNotNil(minRow.indexPath) 42 | XCTAssertNotNil(maxRow.indexPath) 43 | XCTAssertNotNil(minMaxRow.indexPath) 44 | 45 | // make sure cellSetup is called for each cell 46 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: minRow.indexPath!) 47 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: maxRow.indexPath!) 48 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: minMaxRow.indexPath!) 49 | 50 | //make sure cell update is called for each cell 51 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: minRow.indexPath!) 52 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: maxRow.indexPath!) 53 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: minMaxRow.indexPath!) 54 | 55 | XCTAssertNil(minRow.cell.datePicker.maximumDate) 56 | XCTAssertEqual(minRow.cell.datePicker.minimumDate, minRow.value?.addingTimeInterval(-60*60*24)) 57 | XCTAssertNil(maxRow.cell.datePicker.minimumDate) 58 | XCTAssertEqual(maxRow.cell.datePicker.maximumDate, maxRow.value?.addingTimeInterval(60*60*24)) 59 | 60 | XCTAssertNotNil(minMaxRow.cell.datePicker.minimumDate) 61 | XCTAssertEqual(minMaxRow.cell.datePicker.maximumDate, minMaxRow.cell.datePicker.minimumDate!.addingTimeInterval(2*60*60*24)) 62 | } 63 | 64 | func testInterval() { 65 | let row: DateRow? = formVC.form.rowBy(tag: "IntervalDateRow_d1") 66 | 67 | XCTAssertNotNil(row?.indexPath) 68 | 69 | // make sure cellSetup is called for each cell 70 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: row!.indexPath!) 71 | 72 | //make sure cell update is called for each cell 73 | let _ = formVC.tableView(formVC.tableView!, cellForRowAt: row!.indexPath!) 74 | 75 | XCTAssertEqual(row?.cell.datePicker.minuteInterval, 15) 76 | 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 4.3.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Tests/OperatorsTest.swift: -------------------------------------------------------------------------------- 1 | // OperatorsTest.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import XCTest 26 | @testable import Eureka 27 | 28 | class OperatorsTest: BaseEurekaTests { 29 | 30 | func testOperators() { 31 | // test the operators 32 | 33 | var form = Form() 34 | form +++ TextRow("textrow1_ctx") 35 | <<< TextRow("textrow2_ctx") 36 | form = form + (TextRow("textrow3_ctx") 37 | <<< TextRow("textrow4_ctx") 38 | +++ TextRow("textrow5_ctx") 39 | <<< TextRow("textrow6_ctx")) 40 | + (TextRow("textrow7_ctx") 41 | +++ TextRow("textrow8_ctx")) 42 | 43 | XCTAssertEqual(form.count, 5) 44 | XCTAssertEqual(form[0].count, 2) 45 | XCTAssertEqual(form[1].count, 2) 46 | XCTAssertEqual(form[2].count, 2) 47 | 48 | form +++ IntRow("introw1_ctx") 49 | form +++ IntRow("introw2_ctx") 50 | <<< IntRow("introw3_ctx") 51 | <<< IntRow("introw4_ctx") 52 | 53 | // form: 54 | // text1 55 | // text2 56 | // ----- 57 | // text3 58 | // text4 59 | // ----- 60 | // text5 61 | // text6 62 | // ----- 63 | // text7 64 | // ----- 65 | // text8 66 | // ----- 67 | // int1 68 | // ---- 69 | // int2 70 | // int3 71 | // int4 72 | 73 | XCTAssertEqual(form.count, 7) 74 | XCTAssertEqual(form[0].count, 2) 75 | XCTAssertEqual(form[1].count, 2) 76 | XCTAssertEqual(form[2].count, 2) 77 | XCTAssertEqual(form[3].count, 1) 78 | XCTAssertEqual(form[4].count, 1) 79 | XCTAssertEqual(form[5].count, 1) 80 | XCTAssertEqual(form[6].count, 3) 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /Tests/RowByTagTests.swift: -------------------------------------------------------------------------------- 1 | // RowByTagTests.swift 2 | // Eureka ( https://github.com/xmartlabs/Eureka ) 3 | // 4 | // Copyright (c) 2016 Xmartlabs ( http://xmartlabs.com ) 5 | // 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | 25 | import XCTest 26 | @testable import Eureka 27 | 28 | class RowByTagTests: XCTestCase { 29 | 30 | var form: Form! 31 | 32 | override func setUp() { 33 | super.setUp() 34 | 35 | form = Form() 36 | let section = Section() 37 | 38 | form +++ section 39 | 40 | section <<< LabelRow("LabelRow") 41 | section <<< ButtonRow("ButtonRow") 42 | section <<< ActionSheetRow("ActionSheetRow") 43 | section <<< AlertRow("AlertRow") 44 | section <<< PushRow("PushRow") 45 | } 46 | 47 | override func tearDown() { 48 | // Put teardown code here. This method is called after the invocation of each test method in the class. 49 | super.tearDown() 50 | } 51 | 52 | func testRowByTag() { 53 | 54 | let labelRow: LabelRow? = form.rowBy(tag: "LabelRow") 55 | XCTAssertNotNil(labelRow) 56 | 57 | let buttonRow: ButtonRow? = form.rowBy(tag: "ButtonRow") 58 | XCTAssertNotNil(buttonRow) 59 | 60 | let actionSheetRow: ActionSheetRow? = form.rowBy(tag: "ActionSheetRow") 61 | XCTAssertNotNil(actionSheetRow) 62 | 63 | let alertRow: AlertRow? = form.rowBy(tag: "AlertRow") 64 | XCTAssertNotNil(alertRow) 65 | 66 | let pushRow: PushRow? = form.rowBy(tag: "PushRow") 67 | XCTAssertNotNil(pushRow) 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xmartlabs/Eureka/028ef8e3191a256b8f6b8bb6b9496efcb0762dbc/donate.png --------------------------------------------------------------------------------