From 9fada5f4f9fbdc7ff26d11ef9932fe926cb50c91 Mon Sep 17 00:00:00 2001 From: Martin Barreto Date: Thu, 21 May 2015 12:46:38 -0300 Subject: [PATCH] swift examples added. --- .../AccessoryViewFormViewController.swift | 250 +++++++++++ .../CustomRows/CustomRowsViewController.swift | 109 +++++ .../FloatLabeledTextFieldCell.swift | 140 ++++++ .../Rating/RatingView/XLRatingView.swift | 48 ++ .../CustomRows/Rating/XLFormRatingCell.swift | 56 +++ .../CustomRows/Rating/XLFormRatingCell.xib | 56 +++ .../Weekdays/XLFormWeekDaysCell.swift | 135 ++++++ .../Weekdays/XLFormWeekDaysCell.xib | 249 +++++++++++ .../Dates/DateAndTimeValueTrasformer.swift | 78 ++++ .../Dates/DatesFormViewController.swift | 116 ++++- .../Examples/ExamplesFormViewController.swift | 193 ++++++++ .../Inputs/InputsFormViewController.swift | 148 +++++++ .../MultivaluedFormViewController.swift | 278 ++++++++++++ .../Others/CustomCells/XLFormCustomCell.swift | 60 +++ .../Others/OthersFormViewController.swift | 188 ++++++++ .../BasicPredicateViewController.swift | 84 ++++ .../BlogExampleViewController.swift | 92 ++++ .../PredicateFormViewController.swift | 112 +++++ .../NativeEventFormViewController.swift | 263 +++++++++++ ...troller+NativeEvetFormViewController.swift | 13 + .../CustomSelectorsFormViewController.swift | 73 +++ .../CLLocationValueTrasformer.swift | 48 ++ .../MapViewController.swift | 108 +++++ .../MapViewController.xib | 20 + .../DynamicSelectorsFormViewController.swift | 66 +++ .../UsersTableViewController.swift | 204 +++++++++ .../Model.xcdatamodel/contents | 11 + .../Helpers/Data/Store/CoreDataStore.h | 53 +++ .../Helpers/Data/Store/CoreDataStore.m | 227 ++++++++++ .../Selectors/Helpers/Data/User+Additions.h | 41 ++ .../Selectors/Helpers/Data/User+Additions.m | 87 ++++ .../Examples/Selectors/Helpers/Data/User.h | 36 ++ .../Examples/Selectors/Helpers/Data/User.m | 35 ++ .../Helpers/DataLoaders/UserLocalDataLoader.h | 30 ++ .../Helpers/DataLoaders/UserLocalDataLoader.m | 60 +++ .../DataLoaders/UserRemoteDataLoader.h | 30 ++ .../DataLoaders/UserRemoteDataLoader.m | 107 +++++ .../Selectors/Helpers/HTTPSessionManager.h | 32 ++ .../Selectors/Helpers/HTTPSessionManager.m | 45 ++ .../SelectorsFormViewController.swift | 415 ++++++++++++++++++ .../iPhoneStoryboard.storyboard | 284 ++++++++++++ .../UICustomizationFormViewController.swift | 90 ++++ ...ValidationExamplesFormViewController.swift | 164 +++++++ Examples/Swift/Podfile | 5 +- .../SwiftExample.xcodeproj/project.pbxproj | 308 +++++++++++-- .../AccessoryViewFormViewController.swift | 197 +++++++++ Examples/Swift/SwiftExample/AppDelegate.swift | 18 +- .../SwiftExample/Base.lproj/LaunchScreen.xib | 41 -- .../SwiftExample/Base.lproj/Main.storyboard | 82 ---- .../CustomRows/CustomRowsViewController.m | 109 +++++ .../FloatLabeledTextFieldCell.m | 187 ++++++++ .../Rating/RatingView/XLRatingView.h | 29 ++ .../Rating/RatingView/XLRatingView.m | 69 +++ .../CustomRows/Rating/XLFormRatingCell.m | 62 +++ .../CustomRows/Rating/XLFormRatingCell.xib | 57 +++ .../CustomRows/Weekdays/XLFormWeekDaysCell.m | 154 +++++++ .../Weekdays/XLFormWeekDaysCell.xib | 250 +++++++++++ .../CustomSelectorsFormViewController.swift | 75 ++++ .../CLLocationValueTrasformer.swift | 49 +++ .../MapViewController.swift | 99 +++++ .../MapViewController.xib | 19 + .../DynamicSelectorsFormViewController.h | 31 ++ .../DynamicSelectorsFormViewController.m | 66 +++ .../DynamicSelectorsFormViewController.swift | 63 +++ .../UsersTableViewController.h | 31 ++ .../UsersTableViewController.m | 245 +++++++++++ .../UsersTableViewController.swift | 245 +++++++++++ .../ExamplesFormViewController.swift | 177 ++++++++ .../AppIcon.appiconset/Contents.json | 21 +- .../AppIcon.appiconset/xl_appicon_120-1.png | Bin 0 -> 1509 bytes .../AppIcon.appiconset/xl_appicon_120.png | Bin 0 -> 1509 bytes .../AppIcon.appiconset/xl_appicon_152.png | Bin 0 -> 1895 bytes .../AppIcon.appiconset/xl_appicon_58.png | Bin 0 -> 808 bytes .../AppIcon.appiconset/xl_appicon_76.png | Bin 0 -> 883 bytes .../AppIcon.appiconset/xl_appicon_80-1.png | Bin 0 -> 931 bytes .../AppIcon.appiconset/xl_appicon_87.png | Bin 0 -> 1100 bytes .../LaunchImage.launchimage/Contents.json | 52 +++ .../LaunchImage.launchimage/xl_splash@2x.png | Bin 0 -> 18636 bytes .../Apu_Nahasapeemapetilon.png | Bin 0 -> 8101 bytes .../Contents.json | 21 + .../Bart_Simpsons.imageset/Bart_Simpsons.png | Bin 0 -> 7243 bytes .../Bart_Simpsons.imageset/Contents.json | 21 + .../Homer_Simpsons.imageset/Contents.json | 21 + .../Homer_Simpsons.png | Bin 0 -> 11157 bytes .../Lisa_Simpsons.imageset/Contents.json | 21 + .../Lisa_Simpsons.imageset/Lisa_Simpsons.png | Bin 0 -> 13369 bytes .../Maggie_Simpsons.imageset/Contents.json | 21 + .../Maggie_Simpsons.png | Bin 0 -> 14193 bytes .../Marge_Simpsons.imageset/Contents.json | 21 + .../Marge_Simpsons.png | Bin 0 -> 11250 bytes .../Montgomery_Burns.imageset/Contents.json | 21 + .../Montgomery_Burns.png | Bin 0 -> 10788 bytes .../Ned_Flanders.imageset/Contents.json | 21 + .../Ned_Flanders.imageset/Ned_Flanders.png | Bin 0 -> 12610 bytes .../Simpsons/Otto_Mann.imageset/Contents.json | 21 + .../Simpsons/Otto_Mann.imageset/Otto_Mann.png | Bin 0 -> 13021 bytes .../default-avatar.imageset/Contents.json | 21 + .../default-avatar@2x.png | Bin 0 -> 7634 bytes .../checkedDay.imageset/Contents.json | 21 + .../checkedDay.imageset/vweekday.png | Bin 0 -> 242387 bytes .../uncheckedDay.imageset/Contents.json | 21 + .../uncheckedDay.imageset/xweekday.png | Bin 0 -> 242668 bytes Examples/Swift/SwiftExample/Info.plist | 4 +- .../Inputs/InputsFormViewController.swift | 157 +++++++ .../MultivaluedFormViewController.swift | 300 +++++++++++++ .../Others/CustomCells/XLFormCustomCell.swift | 57 +++ .../Others/OthersFormViewController.swift | 183 ++++++++ .../BasicPredicateViewController.swift | 83 ++++ .../BlogExampleViewController.swift | 109 +++++ .../PredicateFormViewController.swift | 113 +++++ .../NativeEventFormViewController.swift | 245 +++++++++++ .../SelectorsFormViewController.swift | 288 ++++++++++++ .../iPhoneStoryboard.storyboard | 283 ++++++++++++ .../SwiftExample-Bridging-Header.h | 7 +- .../UICustomizationFormViewController.swift | 95 ++++ ...ValidationExamplesFormViewController.swift | 159 +++++++ 116 files changed, 9826 insertions(+), 184 deletions(-) create mode 100644 Examples/Swift/Examples/AccessoryViews/AccessoryViewFormViewController.swift create mode 100644 Examples/Swift/Examples/CustomRows/CustomRowsViewController.swift create mode 100644 Examples/Swift/Examples/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.swift create mode 100644 Examples/Swift/Examples/CustomRows/Rating/RatingView/XLRatingView.swift create mode 100644 Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.swift create mode 100644 Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.xib create mode 100644 Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.swift create mode 100644 Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.xib create mode 100644 Examples/Swift/Examples/Dates/DateAndTimeValueTrasformer.swift create mode 100644 Examples/Swift/Examples/ExamplesFormViewController.swift create mode 100644 Examples/Swift/Examples/Inputs/InputsFormViewController.swift create mode 100644 Examples/Swift/Examples/MultiValuedSections/MultivaluedFormViewController.swift create mode 100644 Examples/Swift/Examples/Others/CustomCells/XLFormCustomCell.swift create mode 100755 Examples/Swift/Examples/Others/OthersFormViewController.swift create mode 100644 Examples/Swift/Examples/PredicateExamples/BasicPredicateViewController.swift create mode 100644 Examples/Swift/Examples/PredicateExamples/BlogExampleViewController.swift create mode 100644 Examples/Swift/Examples/PredicateExamples/PredicateFormViewController.swift create mode 100644 Examples/Swift/Examples/RealExamples/NativeEventFormViewController.swift create mode 100644 Examples/Swift/Examples/RealExamples/UIFormViewCotroller+NativeEvetFormViewController.swift create mode 100644 Examples/Swift/Examples/Selectors/CustomSelectors/CustomSelectorsFormViewController.swift create mode 100644 Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift create mode 100644 Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.swift create mode 100644 Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.xib create mode 100644 Examples/Swift/Examples/Selectors/DynamicSelector/DynamicSelectorsFormViewController.swift create mode 100644 Examples/Swift/Examples/Selectors/DynamicSelector/UsersTableViewController.swift create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/Model.xcdatamodeld/Model.xcdatamodel/contents create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.m create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.m create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/User.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/Data/User.m create mode 100644 Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.m create mode 100644 Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.m create mode 100644 Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.h create mode 100644 Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.m create mode 100644 Examples/Swift/Examples/Selectors/SelectorsFormViewController.swift create mode 100644 Examples/Swift/Examples/StoryboardExample/iPhoneStoryboard.storyboard create mode 100644 Examples/Swift/Examples/UICustomization/UICustomizationFormViewController.swift create mode 100644 Examples/Swift/Examples/Validations/ValidationExamplesFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/AccessoryViews/AccessoryViewFormViewController.swift delete mode 100644 Examples/Swift/SwiftExample/Base.lproj/LaunchScreen.xib delete mode 100644 Examples/Swift/SwiftExample/Base.lproj/Main.storyboard create mode 100644 Examples/Swift/SwiftExample/CustomRows/CustomRowsViewController.m create mode 100644 Examples/Swift/SwiftExample/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.m create mode 100644 Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.h create mode 100644 Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.m create mode 100644 Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.m create mode 100644 Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.xib create mode 100644 Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.m create mode 100644 Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.xib create mode 100644 Examples/Swift/SwiftExample/CustomSelectors/CustomSelectorsFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift create mode 100644 Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.swift create mode 100644 Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.xib create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.h create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.m create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.h create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.m create mode 100644 Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.swift create mode 100644 Examples/Swift/SwiftExample/ExamplesFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120-1.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_152.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_58.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_76.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_80-1.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_87.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/LaunchImage.launchimage/xl_splash@2x.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Apu_Nahasapeemapetilon.imageset/Apu_Nahasapeemapetilon.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Apu_Nahasapeemapetilon.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Bart_Simpsons.imageset/Bart_Simpsons.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Bart_Simpsons.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Homer_Simpsons.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Lisa_Simpsons.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Maggie_Simpsons.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Maggie_Simpsons.imageset/Maggie_Simpsons.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Marge_Simpsons.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Montgomery_Burns.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Ned_Flanders.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Ned_Flanders.imageset/Ned_Flanders.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Otto_Mann.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/default-avatar.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/Simpsons/default-avatar.imageset/default-avatar@2x.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/checkedDay.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/checkedDay.imageset/vweekday.png create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/uncheckedDay.imageset/Contents.json create mode 100644 Examples/Swift/SwiftExample/Images.xcassets/uncheckedDay.imageset/xweekday.png create mode 100644 Examples/Swift/SwiftExample/Inputs/InputsFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/MultiValuedSections/MultivaluedFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/Others/CustomCells/XLFormCustomCell.swift create mode 100755 Examples/Swift/SwiftExample/Others/OthersFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/PredicateExamples/BasicPredicateViewController.swift create mode 100644 Examples/Swift/SwiftExample/PredicateExamples/BlogExampleViewController.swift create mode 100644 Examples/Swift/SwiftExample/PredicateExamples/PredicateFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/RealExamples/NativeEventFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/SelectorsFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/StoryboardExample/iPhoneStoryboard.storyboard create mode 100644 Examples/Swift/SwiftExample/UICustomization/UICustomizationFormViewController.swift create mode 100644 Examples/Swift/SwiftExample/Validations/ValidationExamplesFormViewController.swift diff --git a/Examples/Swift/Examples/AccessoryViews/AccessoryViewFormViewController.swift b/Examples/Swift/Examples/AccessoryViews/AccessoryViewFormViewController.swift new file mode 100644 index 0000000..255fa79 --- /dev/null +++ b/Examples/Swift/Examples/AccessoryViews/AccessoryViewFormViewController.swift @@ -0,0 +1,250 @@ +// +// AccessoryViewFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "AccessoryViewFormViewController.h" + +//This macro defines if we use predicates to hide rows or do it manually the old way. +//Just comment out if you want it to run without predicates. +#define USE_PREDICATES_FOR_HIDING + +@interface AccessoryViewFormViewController () + +@end + +@implementation AccessoryViewFormViewController +{ +#ifndef USE_PREDICATES_FOR_HIDING + XLFormRowDescriptor * _rowShowAccessoryView; + XLFormRowDescriptor * _rowStopDisableRow; + XLFormRowDescriptor * _rowStopInlineRow; + XLFormRowDescriptor * _rowSkipCanNotBecomeFirstResponderRow; +#endif +} + + +NSString * kAccessoryViewRowNavigationEnabled = @"kRowNavigationEnabled"; +NSString * kAccessoryViewRowNavigationShowAccessoryView = @"kRowNavigationShowAccessoryView"; +NSString * kAccessoryViewRowNavigationStopDisableRow = @"rowNavigationStopDisableRow"; +NSString * kAccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow = @"rowNavigationSkipCanNotBecomeFirstResponderRow"; +NSString * kAccessoryViewRowNavigationStopInlineRow = @"rowNavigationStopInlineRow"; +NSString * kAccessoryViewName = @"name"; +NSString * kAccessoryViewEmail = @"email"; +NSString * kAccessoryViewTwitter = @"twitter"; +NSString * kAccessoryViewUrl = @"url"; +NSString * kAccessoryViewDate = @"date"; +NSString * kAccessoryViewTextView = @"textView"; +NSString * kAccessoryViewCheck = @"check"; +NSString * kAccessoryViewNotes = @"notes"; + + + + +-(id)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + +-(void)initializeForm +{ + XLFormDescriptor * formDescriptor = [XLFormDescriptor formDescriptorWithTitle:@"Accessory View"]; + formDescriptor.rowNavigationOptions = XLFormRowNavigationOptionEnabled; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + XLFormRowDescriptor * switchRow; + + // Configuration section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Row Navigation Settings"]; + section.footerTitle = @"Changing the Settings values you will navigate differently"; + [formDescriptor addFormSection:section]; + + // RowNavigationEnabled + switchRow = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewRowNavigationEnabled rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"Row Navigation Enabled?"]; + switchRow.value = @YES; + [section addFormRow:switchRow]; + + // RowNavigationShowAccessoryView + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewRowNavigationShowAccessoryView rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Show input accessory row?"]; + row.value = @((formDescriptor.rowNavigationOptions & XLFormRowNavigationOptionEnabled) == XLFormRowNavigationOptionEnabled); + [section addFormRow:row]; +#ifdef USE_PREDICATES_FOR_HIDING + row.hidden = [NSString stringWithFormat:@"$%@ == 0", switchRow]; +#else + _rowShowAccessoryView = row; +#endif + + // RowNavigationStopDisableRow + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewRowNavigationStopDisableRow rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Stop when reach disabled row?"]; + row.value = @((formDescriptor.rowNavigationOptions & XLFormRowNavigationOptionStopDisableRow) == XLFormRowNavigationOptionStopDisableRow); + [section addFormRow:row]; +#ifdef USE_PREDICATES_FOR_HIDING + row.hidden = [NSString stringWithFormat:@"$%@ == 0", switchRow]; +#else + _rowStopDisableRow = row; +#endif + + // RowNavigationStopInlineRow + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewRowNavigationStopInlineRow rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Stop when reach inline row?"]; + row.value = @((formDescriptor.rowNavigationOptions & XLFormRowNavigationOptionStopInlineRow) == XLFormRowNavigationOptionStopInlineRow); + [section addFormRow:row]; +#ifdef USE_PREDICATES_FOR_HIDING + row.hidden = [NSString stringWithFormat:@"$%@ == 0", switchRow]; +#else + _rowStopInlineRow = row; +#endif + + // RowNavigationSkipCanNotBecomeFirstResponderRow + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Skip Can Not Become First Responder Row?"]; + row.value = @((formDescriptor.rowNavigationOptions & XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow) == XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow); + [section addFormRow:row]; +#ifdef USE_PREDICATES_FOR_HIDING + row.hidden = [NSString stringWithFormat:@"$%@ == 0", switchRow]; +#else + _rowSkipCanNotBecomeFirstResponderRow = row; +#endif + + + + // Basic Information - Section + section = [XLFormSectionDescriptor formSectionWithTitle:@"TextField Types"]; + section.footerTitle = @"This is a long text that will appear on section footer"; + [formDescriptor addFormSection:section]; + + // Name + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewName rowType:XLFormRowDescriptorTypeText title:@"Name"]; + row.required = YES; + [section addFormRow:row]; + + // Email + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewEmail rowType:XLFormRowDescriptorTypeEmail title:@"Email"]; + // validate the email + [row addValidator:[XLFormValidator emailValidator]]; + [section addFormRow:row]; + + // Twitter + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewTwitter rowType:XLFormRowDescriptorTypeTwitter title:@"Twitter"]; + row.disabled = @YES; + row.value = @"@no_editable"; + [section addFormRow:row]; + + // Url + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewUrl rowType:XLFormRowDescriptorTypeURL title:@"Url"]; + [section addFormRow:row]; + + // Url + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewDate rowType:XLFormRowDescriptorTypeDateInline title:@"Date Inline"]; + row.value = [NSDate new]; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSection]; + [formDescriptor addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewTextView rowType:XLFormRowDescriptorTypeTextView]; + [row.cellConfigAtConfigure setObject:@"TEXT VIEW EXAMPLE" forKey:@"textView.placeholder"]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewCheck rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Ckeck"]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"TextView With Label Example"]; + [formDescriptor addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kAccessoryViewNotes rowType:XLFormRowDescriptorTypeTextView title:@"Notes"]; + [section addFormRow:row]; + + self.form = formDescriptor; +} + + + +#pragma mark - XLFormDescriptorDelegate + +-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; +#ifndef USE_PREDICATES_FOR_HIDING + NSString * kRowNavigationEnabled = @"kRowNavigationEnabled"; + if ([rowDescriptor.tag isEqualToString:kRowNavigationEnabled]){ + if ([[rowDescriptor.value valueData] isEqual:@NO]){ + self.form.rowNavigationOptions = XLFormRowNavigationOptionNone; + [self.form removeFormRowWithTag:kAccessoryViewRowNavigationShowAccessoryView]; + [self.form removeFormRowWithTag:kAccessoryViewRowNavigationStopDisableRow]; + [self.form removeFormRowWithTag:kAccessoryViewRowNavigationStopInlineRow]; + [self.form removeFormRowWithTag:kAccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow]; + } + else{ + self.form.rowNavigationOptions = XLFormRowNavigationOptionEnabled; + _rowShowAccessoryView.value = @YES; + _rowStopDisableRow.value = @NO; + _rowStopInlineRow.value = @NO; + _rowSkipCanNotBecomeFirstResponderRow.value = @NO; + [self.form addFormRow:_rowShowAccessoryView afterRow:rowDescriptor]; + [self.form addFormRow:_rowStopDisableRow afterRow:_rowShowAccessoryView]; + [self.form addFormRow:_rowStopInlineRow afterRow:_rowStopDisableRow]; + [self.form addFormRow:_rowSkipCanNotBecomeFirstResponderRow afterRow:_rowStopInlineRow]; + + } + } + else +#endif + if ([rowDescriptor.tag isEqualToString:kAccessoryViewRowNavigationStopDisableRow]){ + if ([[rowDescriptor.value valueData] isEqual:@(YES)]){ + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptionStopDisableRow; + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptionStopDisableRow); + } + } + else if ([rowDescriptor.tag isEqualToString:kAccessoryViewRowNavigationStopInlineRow]){ + if ([[rowDescriptor.value valueData] isEqual:@(YES)]){ + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptionStopInlineRow; + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptionStopInlineRow); + } + } + else if ([rowDescriptor.tag isEqualToString:kAccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow]){ + if ([[rowDescriptor.value valueData] isEqual:@(YES)]){ + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow; + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptionSkipCanNotBecomeFirstResponderRow); + } + } +} + +-(UIView *)inputAccessoryViewForRowDescriptor:(XLFormRowDescriptor *)rowDescriptor +{ + if ([[[self.form formRowWithTag:kAccessoryViewRowNavigationShowAccessoryView].value valueData] isEqual:@NO]){ + return nil; + } + return [super inputAccessoryViewForRowDescriptor:rowDescriptor]; +} + +@end diff --git a/Examples/Swift/Examples/CustomRows/CustomRowsViewController.swift b/Examples/Swift/Examples/CustomRows/CustomRowsViewController.swift new file mode 100644 index 0000000..8df4f5f --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/CustomRowsViewController.swift @@ -0,0 +1,109 @@ +// CustomRowsViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +class CustomRowsViewController : XLFormViewController { + + private enum Tags : String { + case CustomRowFirstRatingTag = "CustomRowFirstRatingTag" + case CustomRowSecondRatingTag = "CustomRowSecondRatingTag" + case CustomRowFloatLabeledTextFieldTag = "CustomRowFloatLabeledTextFieldTag" + case CustomRowWeekdays = "CustomRowWeekdays" + case CustomRowText = "CustomText" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Custom Rows") + + section = XLFormSectionDescriptor() + section.title = "Ratings" + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.CustomRowFirstRatingTag.rawValue, rowType: XLFormRowDescriptorTypeRate, title: "First Rating") + row.value = 3 + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.CustomRowSecondRatingTag.rawValue, rowType: XLFormRowDescriptorTypeRate, title: "First Rating") + row.value = 1 + section.addFormRow(row) + + // Section Float Labeled Text Field + section = XLFormSectionDescriptor.formSectionWithTitle("Float Labeled Text Field") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.CustomRowFloatLabeledTextFieldTag.rawValue, rowType: XLFormRowDescriptorTypeFloatLabeledTextField, title: "Title") + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.CustomRowFloatLabeledTextFieldTag.rawValue, rowType: XLFormRowDescriptorTypeFloatLabeledTextField, title: "First Name") + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.CustomRowFloatLabeledTextFieldTag.rawValue, rowType: XLFormRowDescriptorTypeFloatLabeledTextField, title: "Last Name") + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Weekdays") + form.addFormSection(section) + + // WeekDays + row = XLFormRowDescriptor(tag: Tags.CustomRowWeekdays.rawValue, rowType: XLFormRowDescriptorTypeWeekDays, title: nil) + row.value = [ + XLFormWeekDaysCell.kSunday: false, + XLFormWeekDaysCell.kMonday: true, + XLFormWeekDaysCell.kTuesday: true, + XLFormWeekDaysCell.kWednesday: false, + XLFormWeekDaysCell.kThursday: false, + XLFormWeekDaysCell.kFriday: false, + XLFormWeekDaysCell.kSaturday: false + ] + section.addFormRow(row) + + + section = XLFormSectionDescriptor() + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.CustomRowText.rawValue, rowType: XLFormRowDescriptorTypeCustom) + // Must set custom cell or add custom cell to cellClassesForRowDescriptorTypes dictionary before XLFormViewController loaded + row.cellClass = XLFormCustomCell.self + section.addFormRow(row) + + self.form = form + } + +} + diff --git a/Examples/Swift/Examples/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.swift b/Examples/Swift/Examples/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.swift new file mode 100644 index 0000000..5bb01d6 --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.swift @@ -0,0 +1,140 @@ +// FloatLabeledTextFieldCell.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + + +let XLFormRowDescriptorTypeFloatLabeledTextField = "XLFormRowDescriptorTypeFloatLabeledTextField" + + +class FloatLabeledTextFieldCell : XLFormBaseCell, UITextFieldDelegate { + + static let kFontSize : CGFloat = 16.0 + + + lazy var floatLabeledTextField: JVFloatLabeledTextField = { + let result = JVFloatLabeledTextField(frame: CGRect.zeroRect) + result.setTranslatesAutoresizingMaskIntoConstraints(false) + result.font = UIFont.systemFontOfSize(kFontSize) + result.floatingLabel.font = UIFont.boldSystemFontOfSize(kFontSize) + result.clearButtonMode = UITextFieldViewMode.WhileEditing + return result + }() + +//Mark: - XLFormDescriptorCell + + override func configure() { + super.configure() + self.selectionStyle = UITableViewCellSelectionStyle.None + self.contentView.addSubview(self.floatLabeledTextField) + self.floatLabeledTextField.delegate = self + self.contentView.addConstraints(self.layoutConstraints()) + } + + override func update() { + super.update() + self.floatLabeledTextField.attributedPlaceholder = NSAttributedString(string: self.rowDescriptor.title, attributes: [NSForegroundColorAttributeName: UIColor.lightGrayColor()]) + + if let value: AnyObject = self.rowDescriptor.value { + self.floatLabeledTextField.text = value.displayText() + } + else { + self.floatLabeledTextField.text = self.rowDescriptor.noValueDisplayText + } + self.floatLabeledTextField.enabled = !self.rowDescriptor.isDisabled() + self.floatLabeledTextField.floatingLabelTextColor = UIColor.lightGrayColor() + self.floatLabeledTextField.alpha = self.rowDescriptor.isDisabled() ? 0.6 : 1.0 + } + + override func formDescriptorCellCanBecomeFirstResponder() -> Bool { + return !self.rowDescriptor.isDisabled() + } + + + override func formDescriptorCellBecomeFirstResponder() -> Bool { + return self.floatLabeledTextField.becomeFirstResponder() + } + + override static func formDescriptorCellHeightForRowDescriptor(rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 55.0 + } + + +//MARK: Helpers + + func layoutConstraints() -> [AnyObject]{ + let views = ["floatLabeledTextField" : self.floatLabeledTextField] + let metrics = ["hMargin": 15.0, "vMargin": 8.0] + var result = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(hMargin)-[floatLabeledTextField]-(hMargin)-|", options:NSLayoutFormatOptions.AlignAllCenterY, metrics:metrics, views:views) + result += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(vMargin)-[floatLabeledTextField]-(vMargin)-|", options:NSLayoutFormatOptions.AlignAllCenterX, metrics:metrics, views:views) + return result + } + + + + + func textFieldDidChange(textField : UITextField) { + if self.floatLabeledTextField == textField { + if self.floatLabeledTextField.text.isEmpty == false { + self.rowDescriptor.value = self.floatLabeledTextField.text + } else { + self.rowDescriptor.value = nil + } + } + } + +//Mark: UITextFieldDelegate + + func textFieldShouldClear(textField: UITextField) -> Bool { + return self.formViewController().textFieldShouldClear(textField) + } + + func textFieldShouldReturn(textField: UITextField) -> Bool { + return self.formViewController().textFieldShouldReturn(textField) + } + + func textFieldShouldBeginEditing(textField: UITextField) -> Bool { + return self.formViewController().textFieldShouldBeginEditing(textField) + } + + + func textFieldShouldEndEditing(textField: UITextField) -> Bool { + return self.formViewController().textFieldShouldEndEditing(textField) + } + + + func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { + return self.formViewController().textField(textField, shouldChangeCharactersInRange: range, replacementString: string) + } + + func textFieldDidBeginEditing(textField: UITextField) { + self.formViewController().textFieldDidBeginEditing(textField) + } + + + func textFieldDidEndEditing(textField: UITextField) { + self.textFieldDidChange(textField) + self.formViewController().textFieldDidEndEditing(textField) + } + +} diff --git a/Examples/Swift/Examples/CustomRows/Rating/RatingView/XLRatingView.swift b/Examples/Swift/Examples/CustomRows/Rating/RatingView/XLRatingView.swift new file mode 100644 index 0000000..1df2080 --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/Rating/RatingView/XLRatingView.swift @@ -0,0 +1,48 @@ +// XLRatingView.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class XLRatingView : AXRatingView { + + override init(frame: CGRect) { + super.init(frame: frame) + + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + + func customize() { + self.baseColor = UIColor(red: (205/255.0), green: (201/255.0), blue: (201/255.0), alpha: 1) + self.highlightColor = UIColor(red: (255/255.0), green: (215/255.0), blue: 0, alpha: 1) + self.markFont = UIFont.systemFontOfSize(23.0) + self.setTranslatesAutoresizingMaskIntoConstraints(false) + self.stepInterval = 1.0 + } + +} + + diff --git a/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.swift b/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.swift new file mode 100644 index 0000000..d970f82 --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.swift @@ -0,0 +1,56 @@ +// XLFormRatingCell.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +let XLFormRowDescriptorTypeRate = "XLFormRowDescriptorTypeRate" + +@objc +class XLFormRatingCell : XLFormBaseCell { + + @IBOutlet weak var rateTitle: UILabel! + @IBOutlet weak var ratingView: XLRatingView! + + + override func configure() { + super.configure() + self.selectionStyle = UITableViewCellSelectionStyle.None + self.ratingView.addTarget(self, action: "rateChanged:", forControlEvents:UIControlEvents.ValueChanged) + } + + + override func update() { + super.update() + self.ratingView.value = self.rowDescriptor.value.floatValue + self.rateTitle.text = self.rowDescriptor.title + self.ratingView.alpha = self.rowDescriptor.isDisabled() ? 0.6 : 1 + self.rateTitle.alpha = self.rowDescriptor.isDisabled() ? 0.6 : 1 + } + +//MARK: Events + + func rateChanged(ratingView : XLRatingView){ + self.rowDescriptor.value = ratingView.value + } + +} diff --git a/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.xib b/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.xib new file mode 100644 index 0000000..dcf76de --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/Rating/XLFormRatingCell.xib @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.swift b/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.swift new file mode 100644 index 0000000..d7b530b --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.swift @@ -0,0 +1,135 @@ +// XLFormWeekDaysCell.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +let XLFormRowDescriptorTypeWeekDays = "XLFormRowDescriptorTypeWeekDays" + + +class XLFormWeekDaysCell : XLFormBaseCell { + + static let kSunday = "sunday" + static let kMonday = "monday" + static let kTuesday = "tuesday" + static let kWednesday = "wednesday" + static let kThursday = "thursday" + static let kFriday = "friday" + static let kSaturday = "saturday" + + @IBOutlet weak var sundayButton: UIButton! + @IBOutlet weak var mondayButton: UIButton! + @IBOutlet weak var tuesdayButton: UIButton! + @IBOutlet weak var wednesdayButton: UIButton! + @IBOutlet weak var thursdayButton: UIButton! + @IBOutlet weak var fridayButton: UIButton! + @IBOutlet weak var saturdayButton: UIButton! + +//MARK: - XLFormDescriptorCell + + override func configure() { + super.configure() + self.selectionStyle = UITableViewCellSelectionStyle.None + self.configureButtons() + } + + + override func update() { + super.update() + self.updateButtons() + } + + override static func formDescriptorCellHeightForRowDescriptor(rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 60 + } + +//MARK: - Action + + @IBAction func dayTapped(sender: UIButton) { + let day = self.getDayFormButton(sender) + sender.selected = !sender.selected + var newValue = self.rowDescriptor.value as! Dictionary + newValue[day] = sender.selected + self.rowDescriptor.value = newValue + } + +//MARK: - Helpers + + func configureButtons() { + for subview in self.contentView.subviews { + if let button : UIButton = subview as? UIButton { + button.setImage(UIImage(named: "uncheckedDay"), forState: UIControlState.Normal) + button.setImage(UIImage(named: "checkedDay"), forState: UIControlState.Selected) + button.adjustsImageWhenHighlighted = false + self.imageTopTitleBottom(button) + } + } + + } + + func updateButtons() { + let value = self.rowDescriptor.value as! Dictionary + self.sundayButton.selected = value[XLFormWeekDaysCell.kSunday]! + self.mondayButton.selected = value[XLFormWeekDaysCell.kMonday]! + self.tuesdayButton.selected = value[XLFormWeekDaysCell.kTuesday]! + self.wednesdayButton.selected = value[XLFormWeekDaysCell.kWednesday]! + self.thursdayButton.selected = value[XLFormWeekDaysCell.kThursday]! + self.fridayButton.selected = value[XLFormWeekDaysCell.kFriday]! + self.saturdayButton.selected = value[XLFormWeekDaysCell.kSaturday]! + + self.sundayButton.alpha = self.rowDescriptor.isDisabled() ? 0.6 : 1 + self.mondayButton.alpha = self.mondayButton.alpha + self.tuesdayButton.alpha = self.mondayButton.alpha + self.wednesdayButton.alpha = self.mondayButton.alpha + self.thursdayButton.alpha = self.mondayButton.alpha + self.fridayButton.alpha = self.mondayButton.alpha + self.saturdayButton.alpha = self.mondayButton.alpha + } + + func imageTopTitleBottom(button: UIButton) { + // the space between the image and text + let spacing : CGFloat = 3.0 + + // lower the text and push it left so it appears centered + // below the image + let imageSize : CGSize = button.imageView!.image!.size + button.titleEdgeInsets = UIEdgeInsets(top: 0.0, left: -imageSize.width, bottom: -(imageSize.height + spacing), right: 0.0) + + // raise the image and push it right so it appears centered + // above the text + let titleSize : CGSize = (button.titleLabel!.text as! NSString).sizeWithAttributes([NSFontAttributeName: button.titleLabel!.font]) + button.imageEdgeInsets = UIEdgeInsetsMake(-(titleSize.height + spacing), 0.0, 0.0, -titleSize.width) + } + + func getDayFormButton(button: UIButton) -> String + { + if button == self.sundayButton { return XLFormWeekDaysCell.kSunday } + if button == self.mondayButton { return XLFormWeekDaysCell.kMonday } + if button == self.tuesdayButton { return XLFormWeekDaysCell.kTuesday } + if button == self.wednesdayButton { return XLFormWeekDaysCell.kWednesday } + if button == self.thursdayButton { return XLFormWeekDaysCell.kThursday } + if button == self.fridayButton { return XLFormWeekDaysCell.kFriday } + return XLFormWeekDaysCell.kSaturday + } + +} + diff --git a/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.xib b/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.xib new file mode 100644 index 0000000..66cb2fd --- /dev/null +++ b/Examples/Swift/Examples/CustomRows/Weekdays/XLFormWeekDaysCell.xib @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/Examples/Dates/DateAndTimeValueTrasformer.swift b/Examples/Swift/Examples/Dates/DateAndTimeValueTrasformer.swift new file mode 100644 index 0000000..c07ce6a --- /dev/null +++ b/Examples/Swift/Examples/Dates/DateAndTimeValueTrasformer.swift @@ -0,0 +1,78 @@ +// +// DateAndTimeValueTransformer.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + + +class DateValueTrasformer : NSValueTransformer { + + override class func transformedValueClass() -> AnyClass { + return NSString.self + } + + + override class func allowsReverseTransformation() -> Bool { + return false + } + + + override func transformedValue(value: AnyObject?) -> AnyObject? { + if let valueData: AnyObject = value { + if valueData.isKindOfClass(NSDate) { + let date = valueData as! NSDate + let dateFormatter = NSDateFormatter() + dateFormatter.dateStyle = NSDateFormatterStyle.FullStyle + dateFormatter.timeStyle = NSDateFormatterStyle.NoStyle + return dateFormatter.stringFromDate(date) + } + } + return nil + } +} + + +class DateTimeValueTrasformer: NSValueTransformer { + + override class func transformedValueClass() -> AnyClass { + return NSString.self + } + + + override class func allowsReverseTransformation() -> Bool { + return false + } + + override func transformedValue(value: AnyObject?) -> AnyObject? { + if let valueData: AnyObject = value { + if valueData.isKindOfClass(NSDate) { + let date = valueData as! NSDate + let dateFormatter = NSDateFormatter() + dateFormatter.dateStyle = NSDateFormatterStyle.MediumStyle + dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle + return dateFormatter.stringFromDate(date) + } + } + return nil + } +} diff --git a/Examples/Swift/Examples/Dates/DatesFormViewController.swift b/Examples/Swift/Examples/Dates/DatesFormViewController.swift index b5b891b..37a26e4 100644 --- a/Examples/Swift/Examples/Dates/DatesFormViewController.swift +++ b/Examples/Swift/Examples/Dates/DatesFormViewController.swift @@ -26,46 +26,138 @@ class DatesFormViewController: XLFormViewController { - struct tag { - static let dateTime = "dateTime" - static let date = "date" - static let time = "time" + private enum Tags : String { + case DateInline = "dateInline" + case TimeInline = "timeInline" + case DateTimeInline = "dateTimeInline" + case CountDownTimerInline = "countDownTimerInline" + case DatePicker = "datePicker" + case Date = "date" + case Time = "time" + case DateTime = "dateTime" + case CountDownTimer = "countDownTimer" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() } required init(coder aDecoder: NSCoder) { - super.init(coder: aDecoder); + super.init(coder: aDecoder) self.initializeForm() } override func viewDidLoad() { super.viewDidLoad() + let barButton = UIBarButtonItem(title: "Disable", style: UIBarButtonItemStyle.Plain, target: self, action: "disableEnable:") + barButton.possibleTitles = Set(["Disable", "Enable"]) + self.navigationItem.rightBarButtonItem = barButton + } + + + func disableEnable(button : UIBarButtonItem) + { + self.form.disabled = !self.form.disabled + button.title = self.form.disabled ? "Enable" : "Disable" + self.tableView.endEditing(true) + self.tableView.reloadData() } func initializeForm() { - var form : XLFormDescriptor + let form : XLFormDescriptor var section : XLFormSectionDescriptor var row : XLFormRowDescriptor - form = XLFormDescriptor.formDescriptorWithTitle("Dates") as XLFormDescriptor + form = XLFormDescriptor(title: "Date & Time") - section = XLFormSectionDescriptor.formSectionWithTitle("Inline Dates") as XLFormSectionDescriptor + section = XLFormSectionDescriptor.formSectionWithTitle("Inline Dates") form.addFormSection(section) // Date - row = XLFormRowDescriptor(tag: tag.date, rowType: XLFormRowDescriptorTypeDateInline, title:"Date") + row = XLFormRowDescriptor(tag: Tags.DateInline.rawValue, rowType: XLFormRowDescriptorTypeDateInline, title:"Date") row.value = NSDate() section.addFormRow(row) // Time - row = XLFormRowDescriptor(tag: tag.time, rowType: XLFormRowDescriptorTypeTimeInline, title: "Time") + row = XLFormRowDescriptor(tag: Tags.TimeInline.rawValue, rowType: XLFormRowDescriptorTypeTimeInline, title: "Time") row.value = NSDate() section.addFormRow(row) // DateTime - row = XLFormRowDescriptor(tag: tag.dateTime, rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Date Time") + row = XLFormRowDescriptor(tag: Tags.DateTimeInline.rawValue, rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Date Time") row.value = NSDate() section.addFormRow(row) - self.form = form; + + // CountDownTimer + row = XLFormRowDescriptor(tag: Tags.CountDownTimerInline.rawValue, rowType:XLFormRowDescriptorTypeCountDownTimerInline, title:"Countdown Timer") + row.value = NSDate() + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Dates") // + form.addFormSection(section) + + + // Date + row = XLFormRowDescriptor(tag: Tags.Date.rawValue, rowType:XLFormRowDescriptorTypeDate, title:"Date") + row.value = NSDate() + row.cellConfigAtConfigure["minimumDate"] = NSDate() + row.cellConfigAtConfigure["maximumDate"] = NSDate(timeIntervalSinceNow: 60*60*24*3) + section.addFormRow(row) + + // Time + row = XLFormRowDescriptor(tag: Tags.Time.rawValue, rowType: XLFormRowDescriptorTypeTime, title: "Time") + row.cellConfigAtConfigure["minuteInterval"] = 10 + row.value = NSDate() + section.addFormRow(row) + + // DateTime + row = XLFormRowDescriptor(tag: Tags.DateTime.rawValue, rowType: XLFormRowDescriptorTypeDateTime, title: "Date Time") + row.value = NSDate() + section.addFormRow(row) + + // CountDownTimer + row = XLFormRowDescriptor(tag: Tags.CountDownTimer.rawValue, rowType: XLFormRowDescriptorTypeCountDownTimer, title: "Countdown Timer") + row.value = NSDate() + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Disabled Dates") + section.footerTitle = "DatesFormViewController.swift" + form.addFormSection(section) + + // Date + row = XLFormRowDescriptor(tag: nil, rowType: XLFormRowDescriptorTypeDate, title: "Date") + row.disabled = NSNumber(bool: true) + row.required = true + row.value = NSDate() + section.addFormRow(row) + + + + section = XLFormSectionDescriptor.formSectionWithTitle("DatePicker") + form.addFormSection(section) + + // DatePicker + row = XLFormRowDescriptor(tag: Tags.DatePicker.rawValue, rowType:XLFormRowDescriptorTypeDatePicker) + row.cellConfigAtConfigure["datePicker.datePickerMode"] = UIDatePickerMode.Date.rawValue + row.value = NSDate() + section.addFormRow(row) + + + self.form = form } + +// MARK: - XLFormDescriptorDelegate + + override func formRowDescriptorValueHasChanged(formRow: XLFormRowDescriptor!, oldValue: AnyObject!, newValue: AnyObject!) { + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + if formRow.tag == Tags.DatePicker.rawValue { + let alertView = UIAlertView(title: "DatePicker", message: "Value Has changed!", delegate: self, cancelButtonTitle: "OK") + alertView.show() + } + } + } diff --git a/Examples/Swift/Examples/ExamplesFormViewController.swift b/Examples/Swift/Examples/ExamplesFormViewController.swift new file mode 100644 index 0000000..0c33fdc --- /dev/null +++ b/Examples/Swift/Examples/ExamplesFormViewController.swift @@ -0,0 +1,193 @@ +// +// ExamplesFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "InputsFormViewController.h" +#import "SelectorsFormViewController.h" +#import "OthersFormViewController.h" +#import "DatesFormViewController.h" +#import "MultiValuedFormViewController.h" +#import "ExamplesFormViewController.h" +#import "NativeEventFormViewController.h" +#import "UICustomizationFormViewController.h" +#import "CustomRowsViewController.h" +#import "AccessoryViewFormViewController.h" +#import "PredicateFormViewController.h" + +NSString * const kTextFieldAndTextView = @"TextFieldAndTextView"; +NSString * const kSelectors = @"Selectors"; +NSString * const kOthes = @"Others"; +NSString * const kDates = @"Dates"; +NSString * const kPredicates = @"BasicPredicates"; +NSString * const kBlogExample = @"BlogPredicates"; +NSString * const kMultivalued = @"Multivalued"; +NSString * const kMultivaluedOnlyReorder = @"MultivaluedOnlyReorder"; +NSString * const kMultivaluedOnlyInsert = @"MultivaluedOnlyInsert"; +NSString * const kMultivaluedOnlyDelete = @"MultivaluedOnlyDelete"; +NSString * const kValidations= @"Validations"; + +@interface ExamplesFormViewController () + +@end + +@implementation ExamplesFormViewController + + +-(instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self){ + [self initializeForm]; + } + return self; +} + + +-(id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self){ + [self initializeForm]; + } + return self; +} + + +#pragma mark - Helper + +-(void)initializeForm +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + form = [XLFormDescriptor formDescriptor]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Real examples"]; + [form addFormSection:section]; + + // NativeEventFormViewController + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"realExamples" rowType:XLFormRowDescriptorTypeButton title:@"iOS Calendar Event Form"]; + row.action.formSegueIdenfifier = @"NativeEventNavigationViewControllerSegue"; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"This form is actually an example"]; + section.footerTitle = @"ExamplesFormViewController.h, Select an option to view another example"; + [form addFormSection:section]; + + + // TextFieldAndTextView + row = [XLFormRowDescriptor formRowDescriptorWithTag:kTextFieldAndTextView rowType:XLFormRowDescriptorTypeButton title:@"Text Fields"]; + row.action.viewControllerClass = [InputsFormViewController class]; + [section addFormRow:row]; + + // Selectors + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectors rowType:XLFormRowDescriptorTypeButton title:@"Selectors"]; + row.action.formSegueIdenfifier = @"SelectorsFormViewControllerSegue"; + [section addFormRow:row]; + + // Dates + row = [XLFormRowDescriptor formRowDescriptorWithTag:kDates rowType:XLFormRowDescriptorTypeButton title:@"Date & Time"]; + row.action.viewControllerClass = [DatesFormViewController class]; + [section addFormRow:row]; + + // Others + row = [XLFormRowDescriptor formRowDescriptorWithTag:kOthes rowType:XLFormRowDescriptorTypeButton title:@"Other Rows"]; + row.action.formSegueIdenfifier = @"OthersFormViewControllerSegue"; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Multivalued example"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivalued rowType:XLFormRowDescriptorTypeButton title:@"Multivalued Sections"]; + row.action.viewControllerClass = [MultivaluedFormViewController class]; + [section addFormRow:row]; + + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivaluedOnlyReorder rowType:XLFormRowDescriptorTypeButton title:@"Multivalued Only Reorder"]; + row.action.viewControllerClass = [MultivaluedOnlyReorderViewController class]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivaluedOnlyInsert rowType:XLFormRowDescriptorTypeButton title:@"Multivalued Only Insert"]; + row.action.viewControllerClass = [MultivaluedOnlyInserViewController class]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivaluedOnlyDelete rowType:XLFormRowDescriptorTypeButton title:@"Multivalued Only Delete"]; + row.action.viewControllerClass = [MultivaluedOnlyDeleteViewController class]; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"UI Customization"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivalued rowType:XLFormRowDescriptorTypeButton title:@"UI Customization"]; + row.action.viewControllerClass = [UICustomizationFormViewController class]; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Custom Rows"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivalued rowType:XLFormRowDescriptorTypeButton title:@"Custom Rows"]; + row.action.viewControllerClass = [CustomRowsViewController class]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Accessory View"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultivalued rowType:XLFormRowDescriptorTypeButton title:@"Accessory Views"]; + row.action.viewControllerClass = [AccessoryViewFormViewController class]; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Validation Examples"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kValidations rowType:XLFormRowDescriptorTypeButton title:@"Validation Examples"]; + row.action.formSegueIdenfifier = @"ValidationExamplesFormViewControllerSegue"; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Using Predicates"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPredicates rowType:XLFormRowDescriptorTypeButton title:@"Very basic predicates"]; + row.action.formSegueIdenfifier = @"BasicPredicateViewControllerSegue"; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPredicates rowType:XLFormRowDescriptorTypeButton title:@"Blog Example Hide predicates"]; + row.action.formSegueIdenfifier = @"BlogExampleViewSegue"; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPredicates rowType:XLFormRowDescriptorTypeButton title:@"Another example"]; + row.action.formSegueIdenfifier = @"PredicateFormViewControllerSegue"; + [section addFormRow:row]; + + self.form = form; + +} + + + +@end diff --git a/Examples/Swift/Examples/Inputs/InputsFormViewController.swift b/Examples/Swift/Examples/Inputs/InputsFormViewController.swift new file mode 100644 index 0000000..e2c2ef6 --- /dev/null +++ b/Examples/Swift/Examples/Inputs/InputsFormViewController.swift @@ -0,0 +1,148 @@ +// +// InputsFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class InputsFormViewController : XLFormViewController { + + + private enum Tags : String { + case Name = "name" + case Email = "email" + case Twitter = "twitter" + case Number = "number" + case Integer = "integer" + case Decimal = "decimal" + case Password = "password" + case Phone = "phone" + case Url = "url" + case TextView = "textView" + case Notes = "notes" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Text Fields") + form.assignFirstResponderOnShow = true + + section = XLFormSectionDescriptor.formSectionWithTitle("TextField Types") + section.footerTitle = "This is a long text that will appear on section footer" + form.addFormSection(section) + + + // Name + row = XLFormRowDescriptor(tag: Tags.Name.rawValue, rowType: XLFormRowDescriptorTypeText, title: "Name") + row.required = true + section.addFormRow(row) + + // Email + row = XLFormRowDescriptor(tag: Tags.Email.rawValue, rowType: XLFormRowDescriptorTypeEmail, title: "Email") + // validate the email + row.addValidator(XLFormValidator.emailValidator()) + section.addFormRow(row) + + // Twitter + row = XLFormRowDescriptor(tag: Tags.Name.rawValue, rowType: XLFormRowDescriptorTypeTwitter, title: "Twitter") + row.disabled = NSNumber(bool: true) + row.value = "@no_editable" + section.addFormRow(row) + + // Number + row = XLFormRowDescriptor(tag: Tags.Number.rawValue, rowType: XLFormRowDescriptorTypeNumber, title: "Number") + section.addFormRow(row) + + // Integer + row = XLFormRowDescriptor(tag: Tags.Integer.rawValue, rowType: XLFormRowDescriptorTypeInteger, title: "Integer") + section.addFormRow(row) + + // Decimal + row = XLFormRowDescriptor(tag: Tags.Decimal.rawValue, rowType: XLFormRowDescriptorTypeDecimal, title: "Decimal") + section.addFormRow(row) + + // Password + row = XLFormRowDescriptor(tag: Tags.Password.rawValue, rowType: XLFormRowDescriptorTypePassword, title: "Password") + section.addFormRow(row) + + // Phone + row = XLFormRowDescriptor(tag: Tags.Phone.rawValue, rowType: XLFormRowDescriptorTypePhone, title: "Phone") + section.addFormRow(row) + + // Url + row = XLFormRowDescriptor(tag: Tags.Url.rawValue, rowType: XLFormRowDescriptorTypeURL, title: "Url") + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + + // TextView + row = XLFormRowDescriptor(tag: Tags.TextView.rawValue, rowType: XLFormRowDescriptorTypeTextView) + row.cellConfigAtConfigure["textView.placeholder"] = "TEXT VIEW EXAMPLE" + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("TextView With Label Example") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.Number.rawValue, rowType: XLFormRowDescriptorTypeTextView, title: "Notes") + section.addFormRow(row) + + self.form = form + + } + + override func viewDidLoad() + { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Save, target: self, action: "savePressed:") + } + + func savePressed(button: UIBarButtonItem) + { + let validationErrors : Array = self.formValidationErrors() as! Array + if (validationErrors.count > 0){ + self.showFormValidationError(validationErrors.first) + return + } + self.tableView.endEditing(true) + let alertView = UIAlertView(title: "Valid Form", message: "No errors found", delegate: self, cancelButtonTitle: "OK") + alertView.show() + } + +} diff --git a/Examples/Swift/Examples/MultiValuedSections/MultivaluedFormViewController.swift b/Examples/Swift/Examples/MultiValuedSections/MultivaluedFormViewController.swift new file mode 100644 index 0000000..05591e0 --- /dev/null +++ b/Examples/Swift/Examples/MultiValuedSections/MultivaluedFormViewController.swift @@ -0,0 +1,278 @@ +// +// MultiValuedFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "SelectorsFormViewController.h" +#import "MultiValuedFormViewController.h" + + +@implementation MultivaluedFormViewController + +- (id)init +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + form = [XLFormDescriptor formDescriptorWithTitle:@"Multivalued Examples"]; + + // Multivalued section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Multivalued TextField" + sectionOptions:XLFormSectionOptionCanReorder | XLFormSectionOptionCanInsert | XLFormSectionOptionCanDelete + sectionInsertMode:XLFormSectionInsertModeButton]; + section.multivaluedAddButton.title = @"Add New Tag"; + section.footerTitle = @"XLFormSectionInsertModeButton sectionType adds a 'Add Item' (Add New Tag) button row as last cell."; + // set up the row template + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeName]; + [[row cellConfig] setObject:@"Tag Name" forKey:@"textField.placeholder"]; + section.multivaluedRowTemplate = row; + [form addFormSection:section]; + + + // Another Multivalued section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Multivalued ActionSheet Selector example" + sectionOptions:XLFormSectionOptionCanInsert | XLFormSectionOptionCanDelete]; + section.footerTitle = @"XLFormSectionInsertModeLastRow sectionType adds a '+' icon inside last table view cell allowing us to add a new row."; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeSelectorActionSheet title:@"Tap to select.."]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5"]; + [section addFormRow:row]; + + + // Another one + section = [XLFormSectionDescriptor formSectionWithTitle:@"Multivalued Push Selector example" + sectionOptions:XLFormSectionOptionCanInsert | XLFormSectionOptionCanDelete | XLFormSectionOptionCanReorder + sectionInsertMode:XLFormSectionInsertModeButton]; + section.footerTitle = @"MultivaluedFormViewController.h"; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeSelectorPush title:@"Tap to select ;).."]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3"]; + section.multivaluedRowTemplate = [row copy]; + [section addFormRow:row]; + return [super initWithForm:form]; +} + + +-(void)viewDidLoad +{ + [super viewDidLoad]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(addDidTouch:)]; +} + +#pragma mark - Actions + +-(void)addDidTouch:(UIBarButtonItem * __unused)sender +{ + UIActionSheet * actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Remove Last Section" otherButtonTitles:@"Add a section at the end", self.form.isDisabled ? @"Enable Form" : @"Disable Form", nil]; + [actionSheet showInView:self.view]; + +} + +#pragma mark - UIActionSheetDelegate + +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +{ + if ([actionSheet destructiveButtonIndex] == buttonIndex){ + if (self.form.formSections.count > 0){ + // remove last section + [self.form removeFormSectionAtIndex:(self.form.formSections.count - 1)]; + } + } + else if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:@"Add a section at the end"]){ + // add a new section + XLFormSectionDescriptor * newSection = [XLFormSectionDescriptor formSectionWithTitle:[NSString stringWithFormat:@"Section created at %@", [NSDateFormatter localizedStringFromDate:[NSDate new] dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterShortStyle]] sectionOptions:XLFormSectionOptionCanInsert | XLFormSectionOptionCanDelete]; + newSection.multivaluedTag = [NSString stringWithFormat:@"multivaluedPushSelector_%@", @(self.form.formSections.count)]; + XLFormRowDescriptor * newRow = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeSelectorPush title:@"Tap to select ;).."]; + newRow.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3"]; + [newSection addFormRow:newRow]; + [self.form addFormSection:newSection]; + } + else { + self.form.disabled = !self.form.disabled; + [self.tableView endEditing:YES]; + [self.tableView reloadData]; + } +} + +@end + + +@implementation MultivaluedOnlyReorderViewController + +- (id)init +{ + NSTimeInterval secondsPerDay = 24 * 60 * 60; + NSArray * list = @[@"Today", @"Yesterday", @"Before Yesterday"]; + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + + + form = [XLFormDescriptor formDescriptorWithTitle:@"Only Reorder Examples"]; + + + // Multivalued Section with inline rows - section set up to support only reordering + section = [XLFormSectionDescriptor formSectionWithTitle:@"Reordering Inline Rows" + sectionOptions:XLFormSectionOptionCanReorder]; + section.footerTitle = @"XLFormRowDescriptorTypeDateInline row type"; + [form addFormSection:section]; + + [list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + XLFormRowDescriptor * row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeDateInline]; + row.value = [NSDate dateWithTimeIntervalSinceNow:(-secondsPerDay * idx)]; + row.title = obj; + [section addFormRow:row]; + }]; + + + // Multivalued Section with common rows - section set up to support only reordering + section = [XLFormSectionDescriptor formSectionWithTitle:@"Reordering Rows" + sectionOptions:XLFormSectionOptionCanReorder]; + section.footerTitle = @"XLFormRowDescriptorTypeInfo row type"; + [form addFormSection:section]; + + + [list enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + XLFormRowDescriptor * row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeInfo]; + row.value = [NSDateFormatter localizedStringFromDate:[NSDate dateWithTimeIntervalSinceNow:(-secondsPerDay * idx)] dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle]; + row.title = obj; + [section addFormRow:row]; + }]; + + return [super initWithForm:form]; +} + +@end + + +@implementation MultivaluedOnlyInserViewController + +- (id)init +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + NSArray * nameList = @[@"family", @"male", @"female", @"client"]; + + + form = [XLFormDescriptor formDescriptorWithTitle:@"Multivalued Only Insert"]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"XLFormSectionInsertModeButton" + sectionOptions:XLFormSectionOptionCanInsert + sectionInsertMode:XLFormSectionInsertModeButton]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeText]; + [[row cellConfig] setObject:@"Add a new tag" forKey:@"textField.placeholder"]; + section.multivaluedRowTemplate = row; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"XLFormSectionInsertModeButton With Inline Cells" + sectionOptions:XLFormSectionOptionCanInsert + sectionInsertMode:XLFormSectionInsertModeButton]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeDateInline]; + row.value = [NSDate new]; + row.title = @"Date"; + section.multivaluedRowTemplate = row; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"XLFormSectionInsertModeLastRow" + sectionOptions:XLFormSectionOptionCanInsert + sectionInsertMode:XLFormSectionInsertModeLastRow]; + [form addFormSection:section]; + for (NSString * tag in nameList) { + // add a row to the section, the row will be used to crete new rows. + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeText]; + [[row cellConfig] setObject:@"Add a new tag" forKey:@"textField.placeholder"]; + row.value = tag; + [section addFormRow:row]; + } + + return [super initWithForm:form]; +} + +@end + + +@implementation MultivaluedOnlyDeleteViewController + +- (id)init +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + NSArray * nameList = @[@"family", @"male", @"female", @"client"]; + + + form = [XLFormDescriptor formDescriptor]; + + // MultivaluedSection section + section = [XLFormSectionDescriptor formSectionWithTitle:@"" + sectionOptions:XLFormSectionOptionCanDelete]; + section.footerTitle = @"you can swipe to delete when table.editing = NO (Not Editing)"; + [form addFormSection:section]; + + for (NSString * tag in nameList) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeText]; + [[row cellConfig] setObject:@"Add a new tag" forKey:@"textField.placeholder"]; + row.value = [tag copy]; + [section addFormRow:row]; + } + + // Multivalued Section with inline row. + section = [XLFormSectionDescriptor formSectionWithTitle:@"" + sectionOptions:XLFormSectionOptionCanDelete]; + section.footerTitle = @"you can swipe to delete when table.editing = NO (Not Editing)"; + [form addFormSection:section]; + for (NSUInteger i = 0; i < 4; i++) { + row = [XLFormRowDescriptor formRowDescriptorWithTag:nil rowType:XLFormRowDescriptorTypeSelectorPickerViewInline]; + row.title = @"Tap to select"; + row.value = @"client"; + row.selectorOptions = nameList; + [section addFormRow:row]; + } + + return [super initWithForm:form]; +} + + +-(void)viewDidLoad +{ + [super viewDidLoad]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Editing" style:UIBarButtonItemStylePlain target:self action:@selector(toggleEditing:)]; +} + + +-(void)toggleEditing:(UIBarButtonItem *)barButtonItem +{ + [self.tableView setEditing:!self.tableView.editing animated:YES]; + [barButtonItem setTitle:(self.tableView.editing ? @"Editing" : @"Not Editing")]; +} + +@end + diff --git a/Examples/Swift/Examples/Others/CustomCells/XLFormCustomCell.swift b/Examples/Swift/Examples/Others/CustomCells/XLFormCustomCell.swift new file mode 100644 index 0000000..05cfb54 --- /dev/null +++ b/Examples/Swift/Examples/Others/CustomCells/XLFormCustomCell.swift @@ -0,0 +1,60 @@ +// +// XLFormCustomCell.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLFormCustomCell.h" + +@implementation XLFormCustomCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + } + return self; +} + +- (void)configure +{ + [super configure]; + //override +} + +- (void)update +{ + [super update]; + // override + self.textLabel.text = @"Am a custom cell, select me!"; +} + +-(void)formDescriptorCellDidSelectedWithFormController:(XLFormViewController *)controller +{ + // custom code here + // i.e new behaviour when cell has been selected + self.textLabel.text = [self.textLabel.text isEqualToString:@"I can do any custom behaviour..."] ? @"Am a custom cell, select me!" : @"I can do any custom behaviour..."; + self.rowDescriptor.value = self.textLabel.text; + [self.formViewController.tableView selectRowAtIndexPath:nil animated:YES scrollPosition:UITableViewScrollPositionNone]; +} + +@end diff --git a/Examples/Swift/Examples/Others/OthersFormViewController.swift b/Examples/Swift/Examples/Others/OthersFormViewController.swift new file mode 100755 index 0000000..6d6c962 --- /dev/null +++ b/Examples/Swift/Examples/Others/OthersFormViewController.swift @@ -0,0 +1,188 @@ +// +// OthersFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "MapViewController.h" +#import "OthersFormViewController.h" + +NSString *const kSwitchBool = @"switchBool"; +NSString *const kSwitchCheck = @"switchBool"; +NSString *const kStepCounter = @"stepCounter"; +NSString *const kSlider = @"slider"; +NSString *const kSegmentedControl = @"segmentedControl"; +NSString *const kCustom = @"custom"; +NSString *const kInfo = @"info"; +NSString *const kButton = @"button"; +NSString *const kButtonLeftAligned = @"buttonLeftAligned"; +NSString *const kButtonWithSegueId = @"buttonWithSegueId"; +NSString *const kButtonWithSegueClass = @"buttonWithSegueClass"; +NSString *const kButtonWithNibName = @"buttonWithNibName"; +NSString *const kButtonWithStoryboardId = @"buttonWithStoryboardId"; + + +@implementation OthersFormViewController + + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (id)init +{ + self = [super init]; + if (self){ + [self initializeForm]; + } + return self; +} + +-(void)initializeForm +{ + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Other Cells"]; + XLFormSectionDescriptor * section; + + // Basic Information + section = [XLFormSectionDescriptor formSectionWithTitle:@"Other Cells"]; + section.footerTitle = @"OthersFormViewController.h"; + [form addFormSection:section]; + + // Switch + [section addFormRow:[XLFormRowDescriptor formRowDescriptorWithTag:kSwitchBool rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"Switch"]]; + + // check + [section addFormRow:[XLFormRowDescriptor formRowDescriptorWithTag:kSwitchCheck rowType:XLFormRowDescriptorTypeBooleanCheck title:@"Check"]]; + + // step counter + [section addFormRow:[XLFormRowDescriptor formRowDescriptorWithTag:kStepCounter rowType:XLFormRowDescriptorTypeStepCounter title:@"Step counter"]]; + + // Segmented Control + XLFormRowDescriptor * row = [XLFormRowDescriptor formRowDescriptorWithTag:kSegmentedControl rowType:XLFormRowDescriptorTypeSelectorSegmentedControl title:@"Fruits"]; + row.selectorOptions = @[@"Apple", @"Orange", @"Pear"]; + row.value = @"Pear"; + [section addFormRow:row]; + + + // Slider + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSlider rowType:XLFormRowDescriptorTypeSlider title:@"Slider"]; + row.value = @(30); + [row.cellConfigAtConfigure setObject:@(100) forKey:@"slider.maximumValue"]; + [row.cellConfigAtConfigure setObject:@(10) forKey:@"slider.minimumValue"]; + [row.cellConfigAtConfigure setObject:@(4) forKey:@"steps"]; + [section addFormRow:row]; + + + // Info cell + XLFormRowDescriptor *infoRowDescriptor = [XLFormRowDescriptor formRowDescriptorWithTag:kInfo rowType:XLFormRowDescriptorTypeInfo]; + infoRowDescriptor.title = @"Version"; + infoRowDescriptor.value = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; + [section addFormRow:infoRowDescriptor]; + + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Buttons"]; + section.footerTitle = @"Blue buttons will show a message when Switch is ON"; + [form addFormSection:section]; + + // Button + XLFormRowDescriptor * buttonRow = [XLFormRowDescriptor formRowDescriptorWithTag:kButton rowType:XLFormRowDescriptorTypeButton title:@"Button"]; + [buttonRow.cellConfig setObject:[UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0] forKey:@"textLabel.textColor"]; + buttonRow.action.formSelector = @selector(didTouchButton:); + [section addFormRow:buttonRow]; + + + // Left Button + XLFormRowDescriptor * buttonLeftAlignedRow = [XLFormRowDescriptor formRowDescriptorWithTag:kButtonLeftAligned rowType:XLFormRowDescriptorTypeButton title:@"Button with Block"]; + [buttonLeftAlignedRow.cellConfig setObject:[UIColor colorWithRed:0.0 green:122.0/255.0 blue:1.0 alpha:1.0] forKey:@"textLabel.textColor"]; + [buttonLeftAlignedRow.cellConfig setObject:@(NSTextAlignmentLeft) forKey:@"textLabel.textAlignment"]; + [buttonLeftAlignedRow.cellConfig setObject:@(UITableViewCellAccessoryDisclosureIndicator) forKey:@"accessoryType"]; + buttonLeftAlignedRow.action.formBlock = ^(XLFormRowDescriptor * sender){ + if ([[sender.sectionDescriptor.formDescriptor formRowWithTag:kSwitchBool].value boolValue]){ + UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Switch is ON", nil) message:@"Button has checked the switch value..." delegate:self cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil]; + [alertView show]; + } + [self deselectFormRow:sender]; + }; + [section addFormRow:buttonLeftAlignedRow]; + + // Another Left Button with segue + XLFormRowDescriptor * buttonLeftAlignedWithSegueRow = [XLFormRowDescriptor formRowDescriptorWithTag:kButtonWithSegueClass rowType:XLFormRowDescriptorTypeButton title:@"Button with Segue Class"]; + buttonLeftAlignedWithSegueRow.action.formSegueClass = NSClassFromString(@"UIStoryboardPushSegue"); + buttonLeftAlignedWithSegueRow.action.viewControllerClass = [MapViewController class]; + [section addFormRow:buttonLeftAlignedWithSegueRow]; + + + // Button with SegueId + XLFormRowDescriptor * buttonWithSegueId = [XLFormRowDescriptor formRowDescriptorWithTag:kButtonWithSegueClass rowType:XLFormRowDescriptorTypeButton title:@"Button with Segue Idenfifier"]; + buttonWithSegueId.action.formSegueIdenfifier = @"MapViewControllerSegue"; + [section addFormRow:buttonWithSegueId]; + + + // Another Button using Segue + XLFormRowDescriptor * buttonWithStoryboardId = [XLFormRowDescriptor formRowDescriptorWithTag:kButtonWithStoryboardId rowType:XLFormRowDescriptorTypeButton title:@"Button with StoryboardId"]; + buttonWithStoryboardId.action.viewControllerStoryboardId = @"MapViewController"; + [section addFormRow:buttonWithStoryboardId]; + + // Another Left Button with segue + XLFormRowDescriptor * buttonWithNibName = [XLFormRowDescriptor formRowDescriptorWithTag:kButtonWithNibName + rowType:XLFormRowDescriptorTypeButton + title:@"Button with NibName"]; + buttonWithNibName.action.viewControllerNibName = @"MapViewController"; + [section addFormRow:buttonWithNibName]; + + self.form = form; +} + +-(void)didTouchButton:(XLFormRowDescriptor *)sender +{ + if ([[sender.sectionDescriptor.formDescriptor formRowWithTag:kSwitchBool].value boolValue]){ + UIAlertView * alertView = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Switch is ON", nil) message:@"Button has checked the switch value..." delegate:self cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil]; + [alertView show]; + } + [self deselectFormRow:sender]; +} + +-(void)viewDidLoad +{ + [super viewDidLoad]; + UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithTitle:@"Disable" style:UIBarButtonItemStylePlain + target:self + action:@selector(disableEnable:)]; + barButton.possibleTitles = [NSSet setWithObjects:@"Disable", @"Enable", nil]; + self.navigationItem.rightBarButtonItem = barButton; +} + +-(void)disableEnable:(UIBarButtonItem *)button +{ + self.form.disabled = !self.form.disabled; + [button setTitle:(self.form.disabled ? @"Enable" : @"Disable")]; + [self.tableView endEditing:YES]; + [self.tableView reloadData]; +} + + +@end diff --git a/Examples/Swift/Examples/PredicateExamples/BasicPredicateViewController.swift b/Examples/Swift/Examples/PredicateExamples/BasicPredicateViewController.swift new file mode 100644 index 0000000..64fd686 --- /dev/null +++ b/Examples/Swift/Examples/PredicateExamples/BasicPredicateViewController.swift @@ -0,0 +1,84 @@ +// +// BasicPredicateViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "BasicPredicateViewController.h" + +NSString *const khiderow = @"tag1"; +NSString *const khidesection = @"tag2"; +NSString *const ktext = @"tag3"; + +@implementation BasicPredicateViewController +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + + +- (void)initializeForm +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + form = [XLFormDescriptor formDescriptorWithTitle:@"Basic Predicates"]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"A Section"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:khiderow rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"Show next row"]; + row.value = @0; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:khidesection rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"Show B Section"]; + row.hidden = [NSString stringWithFormat:@"$%@==0", khiderow]; + row.value = @0; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"B Section"]; + section.footerTitle = @"BasicPredicateViewController"; + section.hidden = [NSString stringWithFormat:@"$%@==0", khidesection]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:ktext rowType:XLFormRowDescriptorTypeText title:@""]; + [row.cellConfigAtConfigure setObject:@"Gonna disappear soon!!" forKey:@"textField.placeholder"]; + [section addFormRow:row]; + + self.form = form; +} + +@end diff --git a/Examples/Swift/Examples/PredicateExamples/BlogExampleViewController.swift b/Examples/Swift/Examples/PredicateExamples/BlogExampleViewController.swift new file mode 100644 index 0000000..58b66f4 --- /dev/null +++ b/Examples/Swift/Examples/PredicateExamples/BlogExampleViewController.swift @@ -0,0 +1,92 @@ +// +// BlogExampleViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + + + +class BlogExampleViewController : XLFormViewController { + + private enum Tags : String { + case Hobbies = "hobbies" + case Sport = "sport" + case Film = "films1" + case Film2 = "films2" + case Music = "music" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Blog Example: Hobbies") + + section = XLFormSectionDescriptor() + section.title = "Hobbies" + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.Hobbies.rawValue, rowType: XLFormRowDescriptorTypeMultipleSelector, title:"Select Hobbies") + row.selectorOptions = ["Sport", "Music", "Films"] + row.value = [] + section.addFormRow(row) + + section = XLFormSectionDescriptor() + section.title = "Some more questions" + section.hidden = NSPredicate(format: "$\(row.description).value.@count == 0") + section.footerTitle = "BlogExampleViewController.swift" + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.Sport.rawValue, rowType: XLFormRowDescriptorTypeTextView, title:"Your favourite sportsman?") + row.hidden = "NOT $\(Tags.Hobbies.rawValue).value contains 'Sport'" + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.Film.rawValue, rowType:XLFormRowDescriptorTypeTextView, title: "Your favourite film?") + row.hidden = "NOT $\(Tags.Hobbies.rawValue) contains 'Films'" + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.Film2.rawValue, rowType:XLFormRowDescriptorTypeTextView, title:"Your favourite actor?") + row.hidden = "NOT $\(Tags.Hobbies.rawValue) contains 'Films'" + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.Music.rawValue, rowType:XLFormRowDescriptorTypeTextView, title:"Your favourite singer?") + row.hidden = "NOT $\(Tags.Hobbies.rawValue) contains 'Music'" + section.addFormRow(row) + + self.form = form + } + +} diff --git a/Examples/Swift/Examples/PredicateExamples/PredicateFormViewController.swift b/Examples/Swift/Examples/PredicateExamples/PredicateFormViewController.swift new file mode 100644 index 0000000..0a1a4dc --- /dev/null +++ b/Examples/Swift/Examples/PredicateExamples/PredicateFormViewController.swift @@ -0,0 +1,112 @@ +// +// PredicateFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class PredicateFormViewController : XLFormViewController { + + private enum Tags : String { + case Text = "text" + case Integer = "integer" + case Switch = "switch" + case Date = "date" + case Account = "account" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Predicates example") + + section = XLFormSectionDescriptor() + section.title = "Independent rows" + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.Text.rawValue, rowType: XLFormRowDescriptorTypeAccount, title:"Text") + row.cellConfigAtConfigure["textField.placeholder"] = "Type disable" + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.Integer.rawValue, rowType: XLFormRowDescriptorTypeInteger, title:"Integer") + row.hidden = NSPredicate(format: "$\(Tags.Switch.rawValue).value==0") + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.Switch.rawValue, rowType: XLFormRowDescriptorTypeBooleanSwitch, title:"Boolean") + row.value = true + section.addFormRow(row) + + form.addFormSection(section) + + section = XLFormSectionDescriptor() + section.title = "Dependent section" + section.footerTitle = "Type disable in the textfield, a number between 18 and 60 in the integer field or use the switch to disable the last row. By doing all three the last section will hide.\nThe integer field hides when the boolean switch is set to 0." + form.addFormSection(section) + + // Predicate Disabling + row = XLFormRowDescriptor(tag: Tags.Date.rawValue, rowType: XLFormRowDescriptorTypeDateInline, title:"Disabled") + row.value = NSDate.new() + section.addFormRow(row) + row.disabled = NSPredicate(format: "$\(Tags.Text.rawValue).value contains[c] 'disable' OR ($\(Tags.Integer.rawValue).value between {18, 60}) OR ($\(Tags.Switch.rawValue).value == 0)") + section.hidden = NSPredicate(format: "($\(Tags.Text.rawValue).value contains[c] 'disable') AND ($\(Tags.Integer.rawValue).value between {18, 60}) AND ($\(Tags.Switch.rawValue).value == 0)") + + + + section = XLFormSectionDescriptor() + section.title = "More predicates..." + section.footerTitle = "This row hides when the row of the previous section is disabled and the textfield in the first section contains \"out\"\n\nPredicateFormViewController.swift" + form.addFormSection(section) + + + + row = XLFormRowDescriptor(tag: "thirds", rowType:XLFormRowDescriptorTypeAccount, title:"Account") + section.addFormRow(row) + row.hidden = NSPredicate(format: "$\(Tags.Date.rawValue).isDisabled == 1 AND $\(Tags.Text.rawValue).value contains[c] 'Out'") + + self.form = form + } + +} + + + + + + + + + + + diff --git a/Examples/Swift/Examples/RealExamples/NativeEventFormViewController.swift b/Examples/Swift/Examples/RealExamples/NativeEventFormViewController.swift new file mode 100644 index 0000000..32effb8 --- /dev/null +++ b/Examples/Swift/Examples/RealExamples/NativeEventFormViewController.swift @@ -0,0 +1,263 @@ +// +// NativeEventNavigationViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "DateAndTimeValueTrasformer.h" +#import "NativeEventFormViewController.h" + + +@implementation NativeEventNavigationViewController + +-(id)init +{ + self = [super initWithRootViewController:[[NativeEventFormViewController alloc] init]]; + return self; +} + +-(void)viewDidLoad +{ + [super viewDidLoad]; + [self.view setTintColor:[UIColor redColor]]; +} + +@end + +@interface NativeEventFormViewController () + +@end + +@implementation NativeEventFormViewController + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + + +- (void)initializeForm +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + form = [XLFormDescriptor formDescriptorWithTitle:@"Add Event"]; + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Title + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"Title" rowType:XLFormRowDescriptorTypeText]; + [row.cellConfigAtConfigure setObject:@"Title" forKey:@"textField.placeholder"]; + row.required = YES; + [section addFormRow:row]; + + // Location + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"location" rowType:XLFormRowDescriptorTypeText]; + [row.cellConfigAtConfigure setObject:@"Location" forKey:@"textField.placeholder"]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // All-day + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"all-day" rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"All-day"]; + [section addFormRow:row]; + + // Starts + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"starts" rowType:XLFormRowDescriptorTypeDateTimeInline title:@"Starts"]; + row.value = [NSDate dateWithTimeIntervalSinceNow:60*60*24]; + [section addFormRow:row]; + + // Ends + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"ends" rowType:XLFormRowDescriptorTypeDateTimeInline title:@"Ends"]; + row.value = [NSDate dateWithTimeIntervalSinceNow:60*60*25]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Repeat + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"repeat" rowType:XLFormRowDescriptorTypeSelectorPush title:@"Repeat"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Never"]; + row.selectorTitle = @"Repeat"; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Never"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Every Day"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Every Week"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Every 2 Weeks"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Every Month"], + [XLFormOptionsObject formOptionsObjectWithValue:@(5) displayText:@"Every Year"], + ]; + [section addFormRow:row]; + + + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Alert + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"alert" rowType:XLFormRowDescriptorTypeSelectorPush title:@"Alert"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"None"]; + row.selectorTitle = @"Event Alert"; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"None"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"At time of event"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"5 minutes before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"15 minutes before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"30 minutes before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(5) displayText:@"1 hour before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(6) displayText:@"2 hours before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(7) displayText:@"1 day before"], + [XLFormOptionsObject formOptionsObjectWithValue:@(8) displayText:@"2 days before"], + ]; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Show As + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"showAs" rowType:XLFormRowDescriptorTypeSelectorPush title:@"Show As"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Busy"]; + row.selectorTitle = @"Show As"; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Busy"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Free"]]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // URL + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"url" rowType:XLFormRowDescriptorTypeURL]; + [row.cellConfigAtConfigure setObject:@"URL" forKey:@"textField.placeholder"]; + [section addFormRow:row]; + + // Notes + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"notes" rowType:XLFormRowDescriptorTypeTextView]; + [row.cellConfigAtConfigure setObject:@"Notes" forKey:@"textView.placeholder"]; + [section addFormRow:row]; + + + self.form = form; +} + +-(void)viewDidLoad +{ + [super viewDidLoad]; + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelPressed:)]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(savePressed:)]; +} + + +#pragma mark - XLFormDescriptorDelegate + +-(void)formRowDescriptorValueHasChanged:(XLFormRowDescriptor *)rowDescriptor oldValue:(id)oldValue newValue:(id)newValue +{ + [super formRowDescriptorValueHasChanged:rowDescriptor oldValue:oldValue newValue:newValue]; + if ([rowDescriptor.tag isEqualToString:@"alert"]){ + if ([[rowDescriptor.value valueData] isEqualToNumber:@(0)] == NO && [[oldValue valueData] isEqualToNumber:@(0)]){ + + XLFormRowDescriptor * newRow = [rowDescriptor copy]; + newRow.tag = @"secondAlert"; + newRow.title = @"Second Alert"; + [self.form addFormRow:newRow afterRow:rowDescriptor]; + } + else if ([[oldValue valueData] isEqualToNumber:@(0)] == NO && [[newValue valueData] isEqualToNumber:@(0)]){ + [self.form removeFormRowWithTag:@"secondAlert"]; + } + } + else if ([rowDescriptor.tag isEqualToString:@"all-day"]){ + XLFormRowDescriptor * startDateDescriptor = [self.form formRowWithTag:@"starts"]; + XLFormRowDescriptor * endDateDescriptor = [self.form formRowWithTag:@"ends"]; + XLFormDateCell * dateStartCell = (XLFormDateCell *)[[self.form formRowWithTag:@"starts"] cellForFormController:self]; + XLFormDateCell * dateEndCell = (XLFormDateCell *)[[self.form formRowWithTag:@"ends"] cellForFormController:self]; + if ([[rowDescriptor.value valueData] boolValue] == YES){ + startDateDescriptor.valueTransformer = [DateValueTrasformer class]; + endDateDescriptor.valueTransformer = [DateValueTrasformer class]; + [dateStartCell setFormDatePickerMode:XLFormDateDatePickerModeDate]; + [dateEndCell setFormDatePickerMode:XLFormDateDatePickerModeDate]; + } + else{ + startDateDescriptor.valueTransformer = [DateTimeValueTrasformer class]; + endDateDescriptor.valueTransformer = [DateTimeValueTrasformer class]; + [dateStartCell setFormDatePickerMode:XLFormDateDatePickerModeDateTime]; + [dateEndCell setFormDatePickerMode:XLFormDateDatePickerModeDateTime]; + } + [dateStartCell update]; + [dateEndCell update]; + } + else if ([rowDescriptor.tag isEqualToString:@"starts"]){ + XLFormRowDescriptor * startDateDescriptor = [self.form formRowWithTag:@"starts"]; + XLFormRowDescriptor * endDateDescriptor = [self.form formRowWithTag:@"ends"]; + XLFormDateCell * dateEndCell = (XLFormDateCell *)[endDateDescriptor cellForFormController:self]; + if ([startDateDescriptor.value compare:endDateDescriptor.value] == NSOrderedDescending) { + // startDateDescriptor is later than endDateDescriptor + endDateDescriptor.value = [[NSDate alloc] initWithTimeInterval:(60*60*24) sinceDate:startDateDescriptor.value]; + [dateEndCell update]; + } + } + else if ([rowDescriptor.tag isEqualToString:@"ends"]){ + XLFormRowDescriptor * startDateDescriptor = [self.form formRowWithTag:@"starts"]; + XLFormRowDescriptor * endDateDescriptor = [self.form formRowWithTag:@"ends"]; + XLFormDateCell * dateEndCell = (XLFormDateCell *)[endDateDescriptor cellForFormController:self]; + if ([startDateDescriptor.value compare:endDateDescriptor.value] == NSOrderedDescending) { + // startDateDescriptor is later than endDateDescriptor + NSDictionary *strikeThroughAttribute = [NSDictionary dictionaryWithObject:@1 + forKey:NSStrikethroughStyleAttributeName]; + NSAttributedString* strikeThroughText = [[NSAttributedString alloc] initWithString:dateEndCell.detailTextLabel.text attributes:strikeThroughAttribute]; + dateEndCell.detailTextLabel.attributedText = strikeThroughText; + } + } +} + +-(void)cancelPressed:(UIBarButtonItem * __unused)button +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + + +-(void)savePressed:(UIBarButtonItem * __unused)button +{ + NSArray * validationErrors = [self formValidationErrors]; + if (validationErrors.count > 0){ + [self showFormValidationError:[validationErrors firstObject]]; + return; + } + [self.tableView endEditing:YES]; +} + + + +@end diff --git a/Examples/Swift/Examples/RealExamples/UIFormViewCotroller+NativeEvetFormViewController.swift b/Examples/Swift/Examples/RealExamples/UIFormViewCotroller+NativeEvetFormViewController.swift new file mode 100644 index 0000000..f1266e6 --- /dev/null +++ b/Examples/Swift/Examples/RealExamples/UIFormViewCotroller+NativeEvetFormViewController.swift @@ -0,0 +1,13 @@ +// +// UIFormViewCotroller+NativeEvetFormViewController.m +// XLForm +// +// Created by Martin Barreto on 4/2/14. +// Copyright (c) 2014 Xmartlabs. All rights reserved. +// + +#import "UIFormViewCotroller+NativeEvetFormViewController.h" + +@implementation UIFormViewCotroller (NativeEvetFormViewController) + +@end diff --git a/Examples/Swift/Examples/Selectors/CustomSelectors/CustomSelectorsFormViewController.swift b/Examples/Swift/Examples/Selectors/CustomSelectors/CustomSelectorsFormViewController.swift new file mode 100644 index 0000000..a2f96fe --- /dev/null +++ b/Examples/Swift/Examples/Selectors/CustomSelectors/CustomSelectorsFormViewController.swift @@ -0,0 +1,73 @@ +// +// CustomSelectorsFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "CLLocationValueTrasformer.h" +#import "MapViewController.h" + +#import "CustomSelectorsFormViewController.h" + +NSString *const kSelectorMap = @"selectorMap"; +NSString *const kSelectorMapPopover = @"selectorMapPopover"; + +@implementation CustomSelectorsFormViewController + +-(id)init +{ + self = [super init]; + if (self) { + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Custom Selectors"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Basic Information + section = [XLFormSectionDescriptor formSection]; + section.footerTitle = @"CustomSelectorsFormViewController.h"; + [form addFormSection:section]; + + + // Selector Push + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorMap rowType:XLFormRowDescriptorTypeSelectorPush title:@"Coordinate"]; + row.action.viewControllerClass = [MapViewController class]; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){ + // Selector PopOver + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorMapPopover rowType:XLFormRowDescriptorTypeSelectorPopover title:@"Coordinate PopOver"]; + row.action.viewControllerClass = [MapViewController class]; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + } + + self.form = form; + + } + return self; +} + +@end diff --git a/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift new file mode 100644 index 0000000..fa90793 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift @@ -0,0 +1,48 @@ +// +// CLLocationValueTrasformer.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "CLLocationValueTrasformer.h" + +@implementation CLLocationValueTrasformer + ++ (Class)transformedValueClass +{ + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + +- (id)transformedValue:(id)value +{ + if (!value) return nil; + CLLocation * location = (CLLocation *)value; + return [NSString stringWithFormat:@"%0.4f, %0.4f", location.coordinate.latitude, location.coordinate.longitude]; +} + +@end diff --git a/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.swift b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.swift new file mode 100644 index 0000000..6681ebd --- /dev/null +++ b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.swift @@ -0,0 +1,108 @@ +// +// MapViewController.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UIView+XLFormAdditions.h" +#import + +#import "MapViewController.h" + + +@interface MapAnnotation : NSObject +@end + +@implementation MapAnnotation +@synthesize coordinate = _coordinate; +-(void)setCoordinate:(CLLocationCoordinate2D)newCoordinate +{ + _coordinate = newCoordinate; +} +@end + +@interface MapViewController () + +@property (nonatomic) MKMapView * mapView; + +@end + +@implementation MapViewController + +@synthesize rowDescriptor = _rowDescriptor; + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. + [self.view addSubview:self.mapView]; + self.mapView.delegate = self; + if (self.rowDescriptor.value){ + [self.mapView setCenterCoordinate:((CLLocation *)self.rowDescriptor.value).coordinate]; + self.title = [NSString stringWithFormat:@"%0.4f, %0.4f", self.mapView.centerCoordinate.latitude, self.mapView.centerCoordinate.longitude]; + MapAnnotation *annotation = [[MapAnnotation alloc] init]; + annotation.coordinate = self.mapView.centerCoordinate; + [self.mapView addAnnotation:annotation]; + } +} + +-(MKMapView *)mapView +{ + if (_mapView) return _mapView; + _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds]; + _mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + return _mapView; +} + +#pragma mark - MKMapViewDelegate + +- (MKAnnotationView *)mapView:(MKMapView *)mapView + viewForAnnotation:(id )annotation { + + MKPinAnnotationView *pinAnnotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation + reuseIdentifier:@"annotation"]; + pinAnnotationView.pinColor = MKPinAnnotationColorRed; + pinAnnotationView.draggable = YES; + pinAnnotationView.animatesDrop = YES; + return pinAnnotationView; +} + +- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view didChangeDragState:(MKAnnotationViewDragState)newState + fromOldState:(MKAnnotationViewDragState)oldState +{ + if (newState == MKAnnotationViewDragStateEnding){ + self.rowDescriptor.value = [[CLLocation alloc] initWithLatitude:view.annotation.coordinate.latitude longitude:view.annotation.coordinate.longitude]; + self.title = [NSString stringWithFormat:@"%0.4f, %0.4f", view.annotation.coordinate.latitude, view.annotation.coordinate.longitude]; + } +} + + +@end diff --git a/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.xib b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.xib new file mode 100644 index 0000000..026be66 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/CustomSelectors/XLFormRowViewController/MapViewController.xib @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/Examples/Selectors/DynamicSelector/DynamicSelectorsFormViewController.swift b/Examples/Swift/Examples/Selectors/DynamicSelector/DynamicSelectorsFormViewController.swift new file mode 100644 index 0000000..565ea7b --- /dev/null +++ b/Examples/Swift/Examples/Selectors/DynamicSelector/DynamicSelectorsFormViewController.swift @@ -0,0 +1,66 @@ +// +// DynamicSelectorsFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UsersTableViewController.h" +#import "DynamicSelectorsFormViewController.h" + +NSString *const kSelectorUser = @"selectorUser"; +NSString *const kSelectorUserPopover = @"kSelectorUserPopover"; + +@implementation DynamicSelectorsFormViewController + + +-(id)init +{ + self = [super init]; + if (self) { + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Selectors"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Basic Information + section = [XLFormSectionDescriptor formSectionWithTitle:@"Dynamic Selectors"]; + section.footerTitle = @"DynamicSelectorsFormViewController.h"; + [form addFormSection:section]; + + + // Selector Push + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorUser rowType:XLFormRowDescriptorTypeSelectorPush title:@"User"]; + row.action.viewControllerClass = [UsersTableViewController class]; + [section addFormRow:row]; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){ + // Selector PopOver + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorUserPopover rowType:XLFormRowDescriptorTypeSelectorPopover title:@"User Popover"]; + row.action.viewControllerClass = [UsersTableViewController class]; + [section addFormRow:row]; + } + self.form = form; + } + return self; +} + + +@end diff --git a/Examples/Swift/Examples/Selectors/DynamicSelector/UsersTableViewController.swift b/Examples/Swift/Examples/Selectors/DynamicSelector/UsersTableViewController.swift new file mode 100644 index 0000000..fa2afe3 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/DynamicSelector/UsersTableViewController.swift @@ -0,0 +1,204 @@ +// +// UsersTableViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class UserCell : UITableViewCell { + + lazy var userImage : UIImageView = { + let tempUserImage = UIImageView() + tempUserImage.setTranslatesAutoresizingMaskIntoConstraints(false) + tempUserImage.layer.masksToBounds = true + tempUserImage.layer.cornerRadius = 10.0 + return tempUserImage + }() + + + lazy var userName : UILabel = { + let tempUserName = UILabel() + tempUserName.setTranslatesAutoresizingMaskIntoConstraints(false) + tempUserName.font = UIFont.systemFontOfSize(15.0) + return tempUserName + }() + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + // Initialization code + + self.contentView.addSubview(self.userImage) + self.contentView.addSubview(self.userName) + + self.contentView.addConstraints(self.layoutConstraints()) + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func setSelected(selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + } + +// MARK: - Layout Constraints + + func layoutConstraints() -> [AnyObject]{ + let views = ["image": self.userImage, "name": self.userName ] + let metrics = [ "imgSize": 50.0, "margin": 12.0] + + var result = NSLayoutConstraint.constraintsWithVisualFormat("H:|-(margin)-[image(imgSize)]-[name]", options:NSLayoutFormatOptions.AlignAllTop, metrics: metrics, views: views) + result += NSLayoutConstraint.constraintsWithVisualFormat("V:|-(margin)-[image(imgSize)]", options:NSLayoutFormatOptions.allZeros, metrics:metrics, views: views) + return result + } + + +} + + +private let _UsersJSONSerializationSharedInstance = UsersJSONSerialization() + +class UsersJSONSerialization { + + lazy var userData : Array? = { + let dataString = + "[" + + "{\"id\":1,\"name\":\"Apu Nahasapeemapetilon\",\"imageName\":\"Apu_Nahasapeemapetilon.png\"}," + + "{\"id\":7,\"name\":\"Bart Simpsons\",\"imageName\":\"Bart_Simpsons.png\"}," + + "{\"id\":8,\"name\":\"Homer Simpsons\",\"imageName\":\"Homer_Simpsons.png\"}," + + "{\"id\":9,\"name\":\"Lisa Simpsons\",\"imageName\":\"Lisa_Simpsons.png\"}," + + "{\"id\":2,\"name\":\"Maggie Simpsons\",\"imageName\":\"Maggie_Simpsons.png\"}," + + "{\"id\":3,\"name\":\"Marge Simpsons\",\"imageName\":\"Marge_Simpsons.png\"}," + + "{\"id\":4,\"name\":\"Montgomery Burns\",\"imageName\":\"Montgomery_Burns.png\"}," + + "{\"id\":5,\"name\":\"Ned Flanders\",\"imageName\":\"Ned_Flanders.png\"}," + + "{\"id\":6,\"name\":\"Otto Mann\",\"imageName\":\"Otto_Mann.png\"}]" + let jsonData = dataString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) + return NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.allZeros, error: nil) as! Array? + }() + + class var sharedInstance: UsersJSONSerialization { + return _UsersJSONSerializationSharedInstance + } + + +} + +class User: NSObject, XLFormOptionObject { + + let userId: Int + let userName : String + let userImage: String + + init(userId: Int, userName: String, userImage: String){ + self.userId = userId + self.userImage = userImage + self.userName = userName + } + + func formDisplayText() -> String! { + return self.userName + } + + func formValue() -> AnyObject! { + return self.userId + } + +} + +class UsersTableViewController : UITableViewController, XLFormRowDescriptorViewController, XLFormRowDescriptorPopoverViewController { + + + var rowDescriptor : XLFormRowDescriptor? + var popoverController : UIPopoverController? + + var userCell : UserCell? + + private let kUserCellIdentifier = "UserCell" + + + override init(style: UITableViewStyle) { + super.init(style: style); + } + + override init!(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func viewDidLoad() { + super.viewDidLoad() + self.tableView.registerClass(UserCell.self, forCellReuseIdentifier: self.kUserCellIdentifier) + self.tableView.tableFooterView = UIView(frame: CGRect.zeroRect) + } + +// MARK: UITableViewDataSource + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return UsersJSONSerialization.sharedInstance.userData!.count + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell: UserCell = tableView.dequeueReusableCellWithIdentifier(self.kUserCellIdentifier, forIndexPath: indexPath) as! UserCell + let usersData = UsersJSONSerialization.sharedInstance.userData! as! Array> + let userData = usersData[indexPath.row] as Dictionary + let userId = userData["id"] as! Int + cell.userName.text = userData["name"] as? String + cell.userImage.image = UIImage(named: (userData["imageName"] as? String)!) + if self.rowDescriptor?.value != nil { + cell.accessoryType = self.rowDescriptor!.value.formValue().isEqual(userId) ? UITableViewCellAccessoryType.Checkmark : UITableViewCellAccessoryType.None + } + return cell; + + } + + override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + return 73.0 + } + + +//MARK: UITableViewDelegate + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + + let usersData = UsersJSONSerialization.sharedInstance.userData! as! Array> + let userData = usersData[indexPath.row] as Dictionary + let user = User(userId: (userData["id"] as! Int), userName: userData["name"] as! String, userImage: userData["imageName"] as! String) + self.rowDescriptor!.value = user; + if let porpOver = self.popoverController { + porpOver.dismissPopoverAnimated(true) + porpOver.delegate?.popoverControllerDidDismissPopover!(porpOver) + } + else if self.parentViewController is UINavigationController { + self.navigationController?.popViewControllerAnimated(true) + } + } + + +} diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/Model.xcdatamodeld/Model.xcdatamodel/contents b/Examples/Swift/Examples/Selectors/Helpers/Data/Model.xcdatamodeld/Model.xcdatamodel/contents new file mode 100644 index 0000000..9c8a091 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/Model.xcdatamodeld/Model.xcdatamodel/contents @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.h b/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.h new file mode 100644 index 0000000..6ca5035 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.h @@ -0,0 +1,53 @@ +// +// CoreDataStore.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import +#import + +@interface CoreDataStore : NSObject + ++(id)defaultStore; + ++ (NSManagedObjectContext *)mainQueueContext; ++ (NSManagedObjectContext *)privateQueueContext; + ++ (void)savePrivateQueueContext; ++ (void)saveMainQueueContext; + ++ (NSManagedObjectID *)managedObjectIDFromString:(NSString *)managedObjectIDString; + +@end + + +@interface NSManagedObject (Additions) + ++(instancetype)findFirstByAttribute:(NSString *)attribute withValue:(id)value inContext:(NSManagedObjectContext *)context; + ++(NSFetchRequest*)fetchRequest; + ++(instancetype)insert:(NSManagedObjectContext *)context; + +@end \ No newline at end of file diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.m b/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.m new file mode 100644 index 0000000..0b9b95f --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/Store/CoreDataStore.m @@ -0,0 +1,227 @@ +// +// CoreDataStore.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "CoreDataStore.h" + +static NSString *const TBCoreDataModelFileName = @"Model"; + +@interface CoreDataStore () + +@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; +@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel; + +@property (strong, nonatomic) NSManagedObjectContext *mainQueueContext; +@property (strong, nonatomic) NSManagedObjectContext *privateQueueContext; + +@end + +@implementation CoreDataStore + + ++ (instancetype)defaultStore { + static CoreDataStore *_defaultStore = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _defaultStore = [[self alloc] init]; + }); + return _defaultStore; +} + +#pragma mark - Singleton Access + ++ (NSManagedObjectContext *)mainQueueContext +{ + return [[self defaultStore] mainQueueContext]; +} + ++ (NSManagedObjectContext *)privateQueueContext +{ + return [[self defaultStore] privateQueueContext]; +} + ++(void)savePrivateQueueContext +{ + NSError * error; + [[self privateQueueContext] save:&error]; + NSAssert(!error, [error localizedDescription]); +} + ++ (void)saveMainQueueContext +{ + NSError * error; + [[self mainQueueContext] save:&error]; + NSAssert(!error, [error localizedDescription]); +} + ++ (NSManagedObjectID *)managedObjectIDFromString:(NSString *)managedObjectIDString +{ + return [[[self defaultStore] persistentStoreCoordinator] managedObjectIDForURIRepresentation:[NSURL URLWithString:managedObjectIDString]]; +} + +#pragma mark - Lifecycle + +- (id)init +{ + self = [super init]; + if (self) { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSavePrivateQueueContext:)name:NSManagedObjectContextDidSaveNotification object:[self privateQueueContext]]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSaveMainQueueContext:) name:NSManagedObjectContextDidSaveNotification object:[self mainQueueContext]]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - Notifications + +- (void)contextDidSavePrivateQueueContext:(NSNotification *)notification +{ + @synchronized(self) { + [self.mainQueueContext performBlock:^{ + for(NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey]) { + [[self.mainQueueContext objectWithID:[object objectID]] willAccessValueForKey:nil]; + } + [self.mainQueueContext mergeChangesFromContextDidSaveNotification:notification]; + }]; + } +} + +- (void)contextDidSaveMainQueueContext:(NSNotification *)notification +{ + @synchronized(self) { + [self.privateQueueContext performBlock:^{ + [self.privateQueueContext mergeChangesFromContextDidSaveNotification:notification]; + }]; + } +} + +#pragma mark - Getters + +- (NSManagedObjectContext *)mainQueueContext +{ + if (!_mainQueueContext) { + _mainQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; + _mainQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; + } + + return _mainQueueContext; +} + +- (NSManagedObjectContext *)privateQueueContext +{ + if (!_privateQueueContext) { + _privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; + _privateQueueContext.persistentStoreCoordinator = self.persistentStoreCoordinator; + } + + return _privateQueueContext; +} + +#pragma mark - Stack Setup + +- (NSPersistentStoreCoordinator *)persistentStoreCoordinator +{ + if (!_persistentStoreCoordinator) { + _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel]; + NSError *error = nil; + + if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self persistentStoreURL] options:[self persistentStoreOptions] error:&error]) { + NSLog(@"Error adding persistent store. %@, %@", error, error.userInfo); + } + } + + return _persistentStoreCoordinator; +} + +- (NSManagedObjectModel *)managedObjectModel +{ + if (!_managedObjectModel) { + NSURL *modelURL = [[NSBundle mainBundle] URLForResource:TBCoreDataModelFileName withExtension:@"momd"]; + _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; + } + + return _managedObjectModel; +} + +- (NSURL *)persistentStoreURL +{ + return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Model.sqlite"]; +} + +- (NSDictionary *)persistentStoreOptions +{ + return @{NSInferMappingModelAutomaticallyOption: @YES, NSMigratePersistentStoresAutomaticallyOption: @YES, NSSQLitePragmasOption: @{@"synchronous": @"OFF"}}; +} + +#pragma mark - Application's Documents directory + +// Returns the URL to the application's Documents directory. +- (NSURL *)applicationDocumentsDirectory +{ + return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; +} + + + + +@end + + +@implementation NSManagedObject (Additions) + + ++(instancetype)findFirstByAttribute:(NSString *)attribute withValue:(id)value inContext:(NSManagedObjectContext *)context +{ + NSString * predicateStr = [NSString stringWithFormat:@"%@ = %%@", attribute]; + NSPredicate * searchByAttValue = [NSPredicate predicateWithFormat:predicateStr argumentArray:@[value]]; + NSFetchRequest * fetchRequest = [self fetchRequest]; + fetchRequest.predicate = searchByAttValue; + fetchRequest.fetchLimit = 1; + NSArray *result = [context executeFetchRequest:fetchRequest error:nil]; + return [result lastObject]; +} + ++(NSFetchRequest*)fetchRequest +{ + return [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass(self)]; +} + ++(NSEntityDescription*)entityDescriptor:(NSManagedObjectContext *)context +{ + return [NSEntityDescription entityForName:NSStringFromClass(self) inManagedObjectContext:context]; +} + ++(instancetype)insert:(NSManagedObjectContext *)context +{ + return [[NSManagedObject alloc] initWithEntity:[self entityDescriptor:context] insertIntoManagedObjectContext:context]; +} + +@end + + + diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.h b/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.h new file mode 100644 index 0000000..d1fc8f3 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.h @@ -0,0 +1,41 @@ +// +// User+Additions.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "User.h" + +@interface User (Additions) + ++ (User *)createOrUpdateWithServiceResult:(NSDictionary *)data inContext:(NSManagedObjectContext *)context; + ++ (UIImage *)defaultProfileImage; + ++ (NSPredicate *)getPredicateBySearchInput:(NSString *)search; + ++ (NSFetchRequest *)getFetchRequest; + ++ (NSFetchRequest *)getFetchRequestBySearchInput:(NSString *)search; + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.m b/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.m new file mode 100644 index 0000000..61241c9 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/User+Additions.m @@ -0,0 +1,87 @@ +// +// User+Additions.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "CoreDataStore.h" +#import "User+Additions.h" + +#define USER_ID @"id" +#define USER_IMAGE_URL @"imageURL" +#define USER_NAME @"name" + + +@implementation User (Additions) + ++ (User *)createOrUpdateWithServiceResult:(NSDictionary *)data inContext:(NSManagedObjectContext *)context; +{ + User *user = [User findFirstByAttribute:@"userId" withValue:data[USER_ID] inContext:context]; + if (!user) + { + user = [User insert:context]; + } + user.userId = data[USER_ID]; + user.userImageURL = data[USER_IMAGE_URL] ; + user.userName = data[USER_NAME]; + return user; +} + ++ (UIImage *)defaultProfileImage +{ + return [UIImage imageNamed:@"default-avatar"]; +} + ++ (NSPredicate *)getPredicateBySearchInput:(NSString *)search { + + if (search && ![search isEqualToString:@""]) { + return [NSPredicate predicateWithFormat:@"userName CONTAINS[cd] %@" , search]; + } + return nil; +} + ++ (NSFetchRequest *)getFetchRequest { + return [User getFetchRequestBySearchInput:nil]; +} + ++ (NSFetchRequest *)getFetchRequestBySearchInput:(NSString *)search { + NSFetchRequest * fetchRequest = [User fetchRequest]; + fetchRequest.predicate = [User getPredicateBySearchInput:search]; + fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"userName" ascending:YES selector:@selector(caseInsensitiveCompare:)]]; + return fetchRequest; +} + +#pragma mark - XLFormOptionObject + +-(NSString *)formDisplayText +{ + return self.userName; +} + +-(id)formValue +{ + return self.userId; +} + + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/User.h b/Examples/Swift/Examples/Selectors/Helpers/Data/User.h new file mode 100644 index 0000000..ec4d467 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/User.h @@ -0,0 +1,36 @@ +// +// User.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + + +@interface User : NSManagedObject + +@property (nonatomic, retain) NSNumber * userId; +@property (nonatomic, retain) NSString * userName; +@property (nonatomic, retain) NSString * userImageURL; + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/Data/User.m b/Examples/Swift/Examples/Selectors/Helpers/Data/User.m new file mode 100644 index 0000000..97cc851 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/Data/User.m @@ -0,0 +1,35 @@ +// +// User.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "User.h" + + +@implementation User + +@dynamic userId; +@dynamic userName; +@dynamic userImageURL; + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.h b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.h new file mode 100644 index 0000000..6b7f72d --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.h @@ -0,0 +1,30 @@ +// +// UserLocalDataLoader.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLLocalDataLoader.h" + +@interface UserLocalDataLoader : XLLocalDataLoader + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.m b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.m new file mode 100644 index 0000000..b783925 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserLocalDataLoader.m @@ -0,0 +1,60 @@ +// +// UserLocalDataLoader.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UserLocalDataLoader.h" +#import "User+Additions.h" +#import "CoreDataStore.h" + +@implementation UserLocalDataLoader +{ + NSString *_searchString; +} + +- (id)init { + self = [super init]; + if (self) { + NSFetchedResultsController * fetchResultController = [[NSFetchedResultsController alloc] initWithFetchRequest:[User getFetchRequest] + managedObjectContext:[CoreDataStore mainQueueContext] + sectionNameKeyPath:nil + cacheName:nil]; + [self setFetchedResultsController:fetchResultController]; + + } + return self; +} + +-(void)changeSearchString:(NSString *)searchString +{ + _searchString = searchString; + [self refreshPredicate]; +} + +- (void)refreshPredicate +{ + [self setPredicate:[User getPredicateBySearchInput:_searchString]]; + +} + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.h b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.h new file mode 100644 index 0000000..eba6bb5 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.h @@ -0,0 +1,30 @@ +// +// UserRemoteDataLoader.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLRemoteDataLoader.h" + +@interface UserRemoteDataLoader : XLRemoteDataLoader + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.m b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.m new file mode 100644 index 0000000..3ad4dc7 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/DataLoaders/UserRemoteDataLoader.m @@ -0,0 +1,107 @@ +// +// UserRemoteDataLoader.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +#import "UserRemoteDataLoader.h" +#import "HTTPSessionManager.h" +#import "CoreDataStore.h" +#import "User+Additions.h" + +@implementation UserRemoteDataLoader + +-(NSString *)URLString +{ + return @"/mobile/users.json"; +} + +-(NSDictionary *)parameters +{ + NSString *filterParam = self.searchString ?: @""; + return @{@"filter" : filterParam, + @"offset" : @(self.offset), + @"limit" : @(self.limit)}; +} + +-(AFHTTPSessionManager *)sessionManager +{ + return [HTTPSessionManager sharedClient]; +} + +-(void)successulDataLoad { + // change flags + // [self fetchedData] contains the data coming from the server + NSArray * itemsArray = [[self fetchedData] objectForKey:kXLRemoteDataLoaderDefaultKeyForNonDictionaryResponse]; + + // This flag indicates if there is more data to load + _hasMoreToLoad = !((itemsArray.count == 0) || (itemsArray.count < _limit && itemsArray.count != 0)); + [[CoreDataStore privateQueueContext] performBlock:^{ + for (NSDictionary *item in itemsArray) { + // Creates or updates the User and the user who created it with the data that came from the server + [User createOrUpdateWithServiceResult:item[@"user"] inContext:[CoreDataStore privateQueueContext]]; + } + [self removeOutdatedData:itemsArray inContext:[CoreDataStore privateQueueContext]]; + [CoreDataStore savePrivateQueueContext]; + }]; + [super successulDataLoad]; +} + + +#pragma mark - Auxiliary Functions + +- (void)removeOutdatedData:(NSArray *)data inContext:(NSManagedObjectContext *)context +{ + // First, remove older data + NSFetchRequest * fetchRequest = [User getFetchRequestBySearchInput:self.searchString]; + + fetchRequest.fetchLimit = self.limit; + fetchRequest.fetchOffset = self.offset; + + NSError *error; + NSArray * oldObjects = [context executeFetchRequest:fetchRequest error:&error]; + + NSArray * arrayToIterate = [oldObjects copy]; + + if (error) { + dispatch_async(dispatch_get_main_queue(), ^{ + UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Error" + message:error.localizedFailureReason ?: error.localizedDescription + delegate:nil + cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil, nil]; + [alertView show]; + }); + return; + } + + for (User *user in arrayToIterate) + { + NSArray *filteredArray = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"user.id == %@" argumentArray:@[user.userId]]]; + if (filteredArray.count == 0) { + // This User no longer exists + [context deleteObject:user]; + } + } +} + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.h b/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.h new file mode 100644 index 0000000..5f1b526 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.h @@ -0,0 +1,32 @@ +// +// HTTPSessionManager.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPSessionManager.h" + +@interface HTTPSessionManager : AFHTTPSessionManager + ++ (HTTPSessionManager *)sharedClient; + +@end diff --git a/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.m b/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.m new file mode 100644 index 0000000..3a1d001 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/Helpers/HTTPSessionManager.m @@ -0,0 +1,45 @@ +// +// HTTPSessionManager.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "HTTPSessionManager.h" + +@implementation HTTPSessionManager + +// Server Base URL +static NSString * const APIBaseURLString = @"http://obscure-refuge-3149.herokuapp.com"; + ++ (instancetype)sharedClient { + static HTTPSessionManager *_sharedClient = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _sharedClient = [[HTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:APIBaseURLString]]; + [_sharedClient.reachabilityManager startMonitoring]; + _sharedClient.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; + }); + + return _sharedClient; +} + +@end diff --git a/Examples/Swift/Examples/Selectors/SelectorsFormViewController.swift b/Examples/Swift/Examples/Selectors/SelectorsFormViewController.swift new file mode 100644 index 0000000..a437d12 --- /dev/null +++ b/Examples/Swift/Examples/Selectors/SelectorsFormViewController.swift @@ -0,0 +1,415 @@ +// +// SelectorsFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "CLLocationValueTrasformer.h" +#import "MapViewController.h" +#import "CustomSelectorsFormViewController.h" +#import "DynamicSelectorsFormViewController.h" +#import "SelectorsFormViewController.h" + +NSString *const kSelectorPush = @"selectorPush"; +NSString *const kSelectorPopover = @"selectorPopover"; +NSString *const kSelectorActionSheet = @"selectorActionSheet"; +NSString *const kSelectorAlertView = @"selectorAlertView"; +NSString *const kSelectorLeftRight = @"selectorLeftRight"; +NSString *const kSelectorPushDisabled = @"selectorPushDisabled"; +NSString *const kSelectorActionSheetDisabled = @"selectorActionSheetDisabled"; +NSString *const kSelectorLeftRightDisabled = @"selectorLeftRightDisabled"; +NSString *const kSelectorPickerView = @"selectorPickerView"; +NSString *const kSelectorPickerViewInline = @"selectorPickerViewInline"; +NSString *const kMultipleSelector = @"multipleSelector"; +NSString *const kMultipleSelectorPopover = @"multipleSelectorPopover"; +NSString *const kDynamicSelectors = @"dynamicSelectors"; +NSString *const kCustomSelectors = @"customSelectors"; +NSString *const kPickerView = @"pickerView"; +NSString *const kSelectorWithSegueId = @"selectorWithSegueId"; +NSString *const kSelectorWithSegueClass = @"selectorWithSegueClass"; +NSString *const kSelectorWithNibName = @"selectorWithNibName"; +NSString *const kSelectorWithStoryboardId = @"selectorWithStoryboardId"; + +#pragma mark - NSValueTransformer + +@interface NSArrayValueTrasformer : NSValueTransformer +@end + +@implementation NSArrayValueTrasformer + ++ (Class)transformedValueClass +{ + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + +- (id)transformedValue:(id)value +{ + if (!value) return nil; + if ([value isKindOfClass:[NSArray class]]){ + NSArray * array = (NSArray *)value; + return [NSString stringWithFormat:@"%@ Item%@", @(array.count), array.count > 1 ? @"s" : @""]; + } + if ([value isKindOfClass:[NSString class]]) + { + return [NSString stringWithFormat:@"%@ - ;) - Transformed", value]; + } + return nil; +} + +@end + + +@interface ISOLanguageCodesValueTranformer : NSValueTransformer +@end + +@implementation ISOLanguageCodesValueTranformer + ++ (Class)transformedValueClass +{ + return [NSString class]; +} + ++ (BOOL)allowsReverseTransformation +{ + return NO; +} + +- (id)transformedValue:(id)value +{ + if (!value) return nil; + if ([value isKindOfClass:[NSString class]]){ + return [[NSLocale currentLocale] displayNameForKey:NSLocaleLanguageCode value:value]; + } + return nil; +} + +@end + + +#pragma mark - SelectorsFormViewController + +@implementation SelectorsFormViewController + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (void)initializeForm +{ + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Selectors"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Basic Information + section = [XLFormSectionDescriptor formSectionWithTitle:@"Selectors"]; + section.footerTitle = @"SelectorsFormViewController.h"; + [form addFormSection:section]; + + + // Selector Push + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorPush rowType:XLFormRowDescriptorTypeSelectorPush title:@"Push"]; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Option 1"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Option 5"] + ]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"]; + [section addFormRow:row]; + + // Selector Popover + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){ + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorPopover rowType:XLFormRowDescriptorTypeSelectorPopover title:@"PopOver"]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.value = @"Option 2"; + [section addFormRow:row]; + } + + // Selector Action Sheet + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorActionSheet rowType:XLFormRowDescriptorTypeSelectorActionSheet title:@"Sheet"]; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Option 1"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Option 5"] + ]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"]; + [section addFormRow:row]; + + + + + // Selector Alert View + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorAlertView rowType:XLFormRowDescriptorTypeSelectorAlertView title:@"Alert View"]; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Option 1"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Option 5"] + ]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"]; + [section addFormRow:row]; + + + + // Selector Left Right + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorLeftRight rowType:XLFormRowDescriptorTypeSelectorLeftRight title:@"Left Right"]; + row.leftRightSelectorLeftOptionSelected = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"]; + + NSArray * rightOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Right Option 1"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Right Option 2"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Right Option 3"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Right Option 4"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Right Option 5"] + ]; + + // create right selectors + NSMutableArray * leftRightSelectorOptions = [[NSMutableArray alloc] init]; + NSMutableArray * mutableRightOptions = [rightOptions mutableCopy]; + [mutableRightOptions removeObjectAtIndex:0]; + XLFormLeftRightSelectorOption * leftRightSelectorOption = [XLFormLeftRightSelectorOption formLeftRightSelectorOptionWithLeftValue:[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Option 1"] httpParameterKey:@"option_1" rightOptions:mutableRightOptions]; + [leftRightSelectorOptions addObject:leftRightSelectorOption]; + + mutableRightOptions = [rightOptions mutableCopy]; + [mutableRightOptions removeObjectAtIndex:1]; + leftRightSelectorOption = [XLFormLeftRightSelectorOption formLeftRightSelectorOptionWithLeftValue:[XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"] httpParameterKey:@"option_2" rightOptions:mutableRightOptions]; + [leftRightSelectorOptions addObject:leftRightSelectorOption]; + + mutableRightOptions = [rightOptions mutableCopy]; + [mutableRightOptions removeObjectAtIndex:2]; + leftRightSelectorOption = [XLFormLeftRightSelectorOption formLeftRightSelectorOptionWithLeftValue:[XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"] httpParameterKey:@"option_3" rightOptions:mutableRightOptions]; + [leftRightSelectorOptions addObject:leftRightSelectorOption]; + + mutableRightOptions = [rightOptions mutableCopy]; + [mutableRightOptions removeObjectAtIndex:3]; + leftRightSelectorOption = [XLFormLeftRightSelectorOption formLeftRightSelectorOptionWithLeftValue:[XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"] httpParameterKey:@"option_4" rightOptions:mutableRightOptions]; + [leftRightSelectorOptions addObject:leftRightSelectorOption]; + + mutableRightOptions = [rightOptions mutableCopy]; + [mutableRightOptions removeObjectAtIndex:4]; + leftRightSelectorOption = [XLFormLeftRightSelectorOption formLeftRightSelectorOptionWithLeftValue:[XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Option 5"] httpParameterKey:@"option_5" rightOptions:mutableRightOptions]; + [leftRightSelectorOptions addObject:leftRightSelectorOption]; + + row.selectorOptions = leftRightSelectorOptions; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Right Option 4"]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorPickerView rowType:XLFormRowDescriptorTypeSelectorPickerView title:@"Picker View"]; + row.selectorOptions = @[[XLFormOptionsObject formOptionsObjectWithValue:@(0) displayText:@"Option 1"], + [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"], + [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"], + [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"], + [XLFormOptionsObject formOptionsObjectWithValue:@(4) displayText:@"Option 5"] + ]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Option 4"]; + [section addFormRow:row]; + + + + // --------- Fixed Controls + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Fixed Controls"]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPickerView rowType:XLFormRowDescriptorTypePicker]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.value = @"Option 1"; + [section addFormRow:row]; + + + + // --------- Inline Selectors + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Inline Selectors"]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultipleSelector rowType:XLFormRowDescriptorTypeSelectorPickerViewInline title:@"Inline Picker View"]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.value = @"Option 6"; + [section addFormRow:row]; + + // --------- MultipleSelector + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Multiple Selectors"]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultipleSelector rowType:XLFormRowDescriptorTypeMultipleSelector title:@"Multiple Selector"]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.value = @[@"Option 1", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + [section addFormRow:row]; + + + // Multiple selector with value tranformer + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultipleSelector rowType:XLFormRowDescriptorTypeMultipleSelector title:@"Multiple Selector"]; + row.selectorOptions = @[@"Option 1", @"Option 2", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.value = @[@"Option 1", @"Option 3", @"Option 4", @"Option 5", @"Option 6"]; + row.valueTransformer = [NSArrayValueTrasformer class]; + [section addFormRow:row]; + + + // Language multiple selector + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultipleSelector rowType:XLFormRowDescriptorTypeMultipleSelector title:@"Multiple Selector"]; + row.selectorOptions = [NSLocale ISOLanguageCodes]; + row.selectorTitle = @"Languages"; + row.valueTransformer = [ISOLanguageCodesValueTranformer class]; + row.value = [NSLocale preferredLanguages]; + [section addFormRow:row]; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){ + // Language multiple selector popover + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMultipleSelectorPopover rowType:XLFormRowDescriptorTypeMultipleSelectorPopover title:@"Multiple Selector PopOver"]; + row.selectorOptions = [NSLocale ISOLanguageCodes]; + row.valueTransformer = [ISOLanguageCodesValueTranformer class]; + row.value = [NSLocale preferredLanguages]; + [section addFormRow:row]; + } + + + // --------- Dynamic Selectors + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Dynamic Selectors"]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kDynamicSelectors rowType:XLFormRowDescriptorTypeButton title:@"Dynamic Selectors"]; + row.action.viewControllerClass = [DynamicSelectorsFormViewController class]; + [section addFormRow:row]; + + // --------- Custom Selectors + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Custom Selectors"]; + [form addFormSection:section]; + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomSelectors rowType:XLFormRowDescriptorTypeButton title:@"Custom Selectors"]; + row.action.viewControllerClass = [CustomSelectorsFormViewController class]; + [section addFormRow:row]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Disabled & Required Selectors"]; + [form addFormSection:section]; + + + + // Disabled Selector Push + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorPushDisabled rowType:XLFormRowDescriptorTypeSelectorPush title:@"Push"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"]; + row.disabled = @YES; + [section addFormRow:row]; + + + + // --------- Disabled Selector Action Sheet + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorActionSheetDisabled rowType:XLFormRowDescriptorTypeSelectorActionSheet title:@"Sheet"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(2) displayText:@"Option 3"]; + row.disabled = @YES; + [section addFormRow:row]; + + // --------- Disabled Selector Left Right + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorLeftRightDisabled rowType:XLFormRowDescriptorTypeSelectorLeftRight title:@"Left Right"]; + row.leftRightSelectorLeftOptionSelected = [XLFormOptionsObject formOptionsObjectWithValue:@(1) displayText:@"Option 2"]; + row.value = [XLFormOptionsObject formOptionsObjectWithValue:@(3) displayText:@"Right Option 4"]; + row.disabled = @YES; + [section addFormRow:row]; + + + // --------- Selector definition types + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Selectors"]; + [form addFormSection:section]; + + // selector with segue class + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorWithSegueClass rowType:XLFormRowDescriptorTypeSelectorPush title:@"Selector with Segue Class"]; + row.action.formSegueClass = NSClassFromString(@"UIStoryboardPushSegue"); + row.action.viewControllerClass = [MapViewController class]; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + + // selector with SegueId + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorWithSegueClass rowType:XLFormRowDescriptorTypeSelectorPush title:@"Selector with Segue Idenfifier"]; + row.action.formSegueIdenfifier = @"MapViewControllerSegue"; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + + // selector using StoryboardId + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorWithStoryboardId rowType:XLFormRowDescriptorTypeSelectorPush title:@"Selector with StoryboardId"]; + row.action.viewControllerStoryboardId = @"MapViewController"; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + + // selector with NibName + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorWithNibName rowType:XLFormRowDescriptorTypeSelectorPush title:@"Selector with NibName"]; + row.action.viewControllerNibName = @"MapViewController"; + row.valueTransformer = [CLLocationValueTrasformer class]; + row.value = [[CLLocation alloc] initWithLatitude:-33 longitude:-56]; + [section addFormRow:row]; + + + + self.form = form; +} + + +-(UIStoryboard *)storyboardForRow:(XLFormRowDescriptor *)formRow +{ + return [UIStoryboard storyboardWithName:@"iPhoneStoryboard" bundle:nil]; +} + + +-(void)viewDidLoad +{ + [super viewDidLoad]; + UIBarButtonItem * barButton = [[UIBarButtonItem alloc] initWithTitle:@"Disable" style:UIBarButtonItemStylePlain + target:self + action:@selector(disableEnable:)]; + barButton.possibleTitles = [NSSet setWithObjects:@"Disable", @"Enable", nil]; + self.navigationItem.rightBarButtonItem = barButton; +} + +-(void)disableEnable:(UIBarButtonItem *)button +{ + self.form.disabled = !self.form.disabled; + [button setTitle:(self.form.disabled ? @"Enable" : @"Disable")]; + [self.tableView endEditing:YES]; + [self.tableView reloadData]; +} + + + +@end diff --git a/Examples/Swift/Examples/StoryboardExample/iPhoneStoryboard.storyboard b/Examples/Swift/Examples/StoryboardExample/iPhoneStoryboard.storyboard new file mode 100644 index 0000000..7318253 --- /dev/null +++ b/Examples/Swift/Examples/StoryboardExample/iPhoneStoryboard.storyboard @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/Examples/UICustomization/UICustomizationFormViewController.swift b/Examples/Swift/Examples/UICustomization/UICustomizationFormViewController.swift new file mode 100644 index 0000000..ea0ea0b --- /dev/null +++ b/Examples/Swift/Examples/UICustomization/UICustomizationFormViewController.swift @@ -0,0 +1,90 @@ +// +// UICustomizationFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "UICustomizationFormViewController.h" + +@implementation UICustomizationFormViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"UI Customization"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + + // Section + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + // Name + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"Name" rowType:XLFormRowDescriptorTypeText title:@"Name"]; + // change the background color + [row.cellConfigAtConfigure setObject:[UIColor greenColor] forKey:@"backgroundColor"]; + // font + [row.cellConfig setObject:[UIFont fontWithName:@"Helvetica" size:30] forKey:@"textLabel.font"]; + // background color + [row.cellConfig setObject:[UIColor grayColor] forKey:@"textField.backgroundColor"]; + // font + [row.cellConfig setObject:[UIFont fontWithName:@"Helvetica" size:25] forKey:@"textField.font"]; + // alignment + [row.cellConfig setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"]; + [section addFormRow:row]; + + + // Section + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + //Button + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"Button" rowType:XLFormRowDescriptorTypeButton title:@"Button"]; + [row.cellConfigAtConfigure setObject:[UIColor purpleColor] forKey:@"backgroundColor"]; + [row.cellConfig setObject:[UIColor whiteColor] forKey:@"textLabel.color"]; + [row.cellConfig setObject:[UIFont fontWithName:@"Helvetica" size:40] forKey:@"textLabel.font"]; + [section addFormRow:row]; + + self.form = form; + } + return self; +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + // change cell height of a particular cell + if ([[self.form formRowAtIndex:indexPath].tag isEqualToString:@"Name"]){ + return 60.0; + } + else if ([[self.form formRowAtIndex:indexPath].tag isEqualToString:@"Button"]){ + return 100.0; + } + return [super tableView:tableView heightForRowAtIndexPath:indexPath]; +} + +@end diff --git a/Examples/Swift/Examples/Validations/ValidationExamplesFormViewController.swift b/Examples/Swift/Examples/Validations/ValidationExamplesFormViewController.swift new file mode 100644 index 0000000..1a6549b --- /dev/null +++ b/Examples/Swift/Examples/Validations/ValidationExamplesFormViewController.swift @@ -0,0 +1,164 @@ +// +// ValidationExamplesFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "ValidationExamplesFormViewController.h" + +@interface ValidationExamplesFormViewController () + +@end + +@implementation ValidationExamplesFormViewController + +NSString * const kValidationName = @"kName"; +NSString * const kValidationEmail = @"kEmail"; +NSString * const kValidationPassword = @"kPassword"; +NSString * const kValidationInteger = @"kInteger"; + + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + + +-(void)initializeForm +{ + XLFormDescriptor * formDescriptor = [XLFormDescriptor formDescriptorWithTitle:@"Text Fields"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Name Section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Validation Required"]; + [formDescriptor addFormSection:section]; + + // Name + row = [XLFormRowDescriptor formRowDescriptorWithTag:kValidationName rowType:XLFormRowDescriptorTypeText title:@"Name"]; + [row.cellConfigAtConfigure setObject:@"Required..." forKey:@"textField.placeholder"]; + [row.cellConfigAtConfigure setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"]; + row.required = YES; + row.value = @"Martin"; + [section addFormRow:row]; + + // Email Section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Validation Email"]; + [formDescriptor addFormSection:section]; + + // Email + row = [XLFormRowDescriptor formRowDescriptorWithTag:kValidationEmail rowType:XLFormRowDescriptorTypeText title:@"Email"]; + [row.cellConfigAtConfigure setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"]; + row.required = NO; + row.value = @"not valid email"; + [row addValidator:[XLFormValidator emailValidator]]; + [section addFormRow:row]; + + // password Section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Validation Password"]; + section.footerTitle = @"between 6 and 32 charachers, 1 alphanumeric and 1 numeric"; + [formDescriptor addFormSection:section]; + + // Password + row = [XLFormRowDescriptor formRowDescriptorWithTag:kValidationPassword rowType:XLFormRowDescriptorTypePassword title:@"Password"]; + [row.cellConfigAtConfigure setObject:@"Required..." forKey:@"textField.placeholder"]; + [row.cellConfigAtConfigure setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"]; + row.required = YES; + [row addValidator:[XLFormRegexValidator formRegexValidatorWithMsg:@"At least 6, max 32 characters" regex:@"^(?=.*\\d)(?=.*[A-Za-z]).{6,32}$"]]; + [section addFormRow:row]; + + // number Section + section = [XLFormSectionDescriptor formSectionWithTitle:@"Validation Numbers"]; + section.footerTitle = @"grather than 50 and less than 100"; + [formDescriptor addFormSection:section]; + + // Integer + row = [XLFormRowDescriptor formRowDescriptorWithTag:kValidationInteger rowType:XLFormRowDescriptorTypeInteger title:@"Integer"]; + [row.cellConfigAtConfigure setObject:@"Required..." forKey:@"textField.placeholder"]; + [row.cellConfigAtConfigure setObject:@(NSTextAlignmentRight) forKey:@"textField.textAlignment"]; + row.required = YES; + [row addValidator:[XLFormRegexValidator formRegexValidatorWithMsg:@"grather than 50 and less than 100" regex:@"^([5-9][0-9]|100)$"]]; + [section addFormRow:row]; + + self.form = formDescriptor; +} + + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + [self.navigationItem.rightBarButtonItem setTarget:self]; + [self.navigationItem.rightBarButtonItem setAction:@selector(validateForm:)]; +} + +#pragma mark - actions + +-(void)validateForm:(UIBarButtonItem *)buttonItem +{ + NSArray * array = [self formValidationErrors]; + [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + XLFormValidationStatus * validationStatus = [[obj userInfo] objectForKey:XLValidationStatusErrorKey]; + if ([validationStatus.rowDescriptor.tag isEqualToString:kValidationName]){ + UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[self.form indexPathOfFormRow:validationStatus.rowDescriptor]]; + cell.backgroundColor = [UIColor orangeColor]; + [UIView animateWithDuration:0.3 animations:^{ + cell.backgroundColor = [UIColor whiteColor]; + }]; + } + else if ([validationStatus.rowDescriptor.tag isEqualToString:kValidationEmail]){ + UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[self.form indexPathOfFormRow:validationStatus.rowDescriptor]]; + [self animateCell:cell]; + } + else if ([validationStatus.rowDescriptor.tag isEqualToString:kValidationPassword]){ + UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[self.form indexPathOfFormRow:validationStatus.rowDescriptor]]; + [self animateCell:cell]; + } + else if ([validationStatus.rowDescriptor.tag isEqualToString:kValidationInteger]){ + UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[self.form indexPathOfFormRow:validationStatus.rowDescriptor]]; + [self animateCell:cell]; + } + }]; +} + + +#pragma mark - Helper + +-(void)animateCell:(UITableViewCell *)cell +{ + CAKeyframeAnimation *animation = [CAKeyframeAnimation animation]; + animation.keyPath = @"position.x"; + animation.values = @[ @0, @20, @-20, @10, @0]; + animation.keyTimes = @[@0, @(1 / 6.0), @(3 / 6.0), @(5 / 6.0), @1]; + animation.duration = 0.3; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + animation.additive = YES; + + [cell.layer addAnimation:animation forKey:@"shake"]; +} + + +@end diff --git a/Examples/Swift/Podfile b/Examples/Swift/Podfile index 0ba7d65..96d1a81 100644 --- a/Examples/Swift/Podfile +++ b/Examples/Swift/Podfile @@ -2,6 +2,9 @@ platform :ios, '8.0' target 'SwiftExample' do -pod 'XLForm', :path => '../../' +pod 'XLForm', :path => '../../' +pod 'XLDataLoader', '~> 1.1', :inhibit_warnings => true +pod 'JVFloatLabeledTextField', '1.0.2', :inhibit_warnings => true +pod 'AXRatingView', '1.0.3', :inhibit_warnings => true end diff --git a/Examples/Swift/SwiftExample.xcodeproj/project.pbxproj b/Examples/Swift/SwiftExample.xcodeproj/project.pbxproj index ac81647..165742a 100644 --- a/Examples/Swift/SwiftExample.xcodeproj/project.pbxproj +++ b/Examples/Swift/SwiftExample.xcodeproj/project.pbxproj @@ -7,26 +7,78 @@ objects = { /* Begin PBXBuildFile section */ - 2724071466166BFA1E54E659 /* libPods-SwiftExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 854F8DF43072D7C59CBECB68 /* libPods-SwiftExample.a */; }; 2847A6A41AAF2679000A2ABE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2847A6A31AAF2679000A2ABE /* AppDelegate.swift */; }; - 2847A6A91AAF2679000A2ABE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2847A6A71AAF2679000A2ABE /* Main.storyboard */; }; 2847A6AB1AAF2679000A2ABE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2847A6AA1AAF2679000A2ABE /* Images.xcassets */; }; - 2847A6AE1AAF2679000A2ABE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2847A6AC1AAF2679000A2ABE /* LaunchScreen.xib */; }; + 2860673E1AEDBD4A002F1E04 /* CustomRowsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286067321AEDBD4A002F1E04 /* CustomRowsViewController.swift */; }; + 2860673F1AEDBD4A002F1E04 /* FloatLabeledTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286067341AEDBD4A002F1E04 /* FloatLabeledTextFieldCell.swift */; }; + 286067411AEDBD4A002F1E04 /* XLFormRatingCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286067391AEDBD4A002F1E04 /* XLFormRatingCell.swift */; }; + 286067421AEDBD4A002F1E04 /* XLFormRatingCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2860673A1AEDBD4A002F1E04 /* XLFormRatingCell.xib */; }; + 286067431AEDBD4A002F1E04 /* XLFormWeekDaysCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2860673C1AEDBD4A002F1E04 /* XLFormWeekDaysCell.swift */; }; + 286067441AEDBD4A002F1E04 /* XLFormWeekDaysCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2860673D1AEDBD4A002F1E04 /* XLFormWeekDaysCell.xib */; }; + 286067461AEDC3D7002F1E04 /* XLRatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286067451AEDC3D7002F1E04 /* XLRatingView.swift */; }; + 286E8B751AE809EF00F2767A /* DynamicSelectorsFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B731AE809EF00F2767A /* DynamicSelectorsFormViewController.swift */; }; + 286E8B781AE80C4300F2767A /* UsersTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B771AE80C4300F2767A /* UsersTableViewController.swift */; }; + 286E8B7E1AE86C8900F2767A /* XLFormCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B7C1AE86C8900F2767A /* XLFormCustomCell.swift */; }; + 286E8B7F1AE86C8900F2767A /* OthersFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B7D1AE86C8900F2767A /* OthersFormViewController.swift */; }; + 286E8B861AE9286B00F2767A /* CustomSelectorsFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B811AE9286B00F2767A /* CustomSelectorsFormViewController.swift */; }; + 286E8B871AE9286B00F2767A /* CLLocationValueTrasformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B831AE9286B00F2767A /* CLLocationValueTrasformer.swift */; }; + 286E8B881AE9286B00F2767A /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B841AE9286B00F2767A /* MapViewController.swift */; }; + 286E8B891AE9286B00F2767A /* MapViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 286E8B851AE9286B00F2767A /* MapViewController.xib */; }; + 286E8B8C1AE9993F00F2767A /* MultivaluedFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 286E8B8B1AE9993F00F2767A /* MultivaluedFormViewController.swift */; }; + 288646151AE59474007A8B9B /* ExamplesFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 288646141AE59474007A8B9B /* ExamplesFormViewController.swift */; }; + 288646181AE5C7EA007A8B9B /* iPhoneStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 288646171AE5C7EA007A8B9B /* iPhoneStoryboard.storyboard */; }; + 2886461C1AE5C958007A8B9B /* NativeEventFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2886461A1AE5C958007A8B9B /* NativeEventFormViewController.swift */; }; + 2886461F1AE5FEB5007A8B9B /* DateAndTimeValueTrasformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2886461E1AE5FEB5007A8B9B /* DateAndTimeValueTrasformer.swift */; }; + 28B920751AE6F02F00BD6382 /* InputsFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B920741AE6F02F00BD6382 /* InputsFormViewController.swift */; }; + 28B920781AE73AA600BD6382 /* SelectorsFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28B920771AE73AA600BD6382 /* SelectorsFormViewController.swift */; }; + 28D832571AEBC4A7009E3B3F /* AccessoryViewFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D832561AEBC4A7009E3B3F /* AccessoryViewFormViewController.swift */; }; + 28D832631AEBE4E4009E3B3F /* BasicPredicateViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D832601AEBE4E4009E3B3F /* BasicPredicateViewController.swift */; }; + 28D832671AEBEAA0009E3B3F /* BlogExampleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D832661AEBEAA0009E3B3F /* BlogExampleViewController.swift */; }; + 28D832691AEBFE9F009E3B3F /* PredicateFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D832681AEBFE9F009E3B3F /* PredicateFormViewController.swift */; }; + 28D8326C1AEC177E009E3B3F /* ValidationExamplesFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D8326B1AEC177E009E3B3F /* ValidationExamplesFormViewController.swift */; }; + 28D8326F1AEC2D1B009E3B3F /* UICustomizationFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28D8326E1AEC2D1B009E3B3F /* UICustomizationFormViewController.swift */; }; 28F490221AAFBBC600C8E0CC /* DatesFormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 28F490211AAFBBC600C8E0CC /* DatesFormViewController.swift */; }; + DD7B43598E698717584375E9 /* libPods-SwiftExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9CFB9BA3A82D5F6FE7CCE5A5 /* libPods-SwiftExample.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 2847A69E1AAF2679000A2ABE /* SwiftExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 2847A6A21AAF2679000A2ABE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2847A6A31AAF2679000A2ABE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 2847A6A81AAF2679000A2ABE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 2847A6A31AAF2679000A2ABE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 2847A6AA1AAF2679000A2ABE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 2847A6AD1AAF2679000A2ABE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 2847A6C31AAF2B14000A2ABE /* SwiftExample-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SwiftExample-Bridging-Header.h"; sourceTree = ""; }; - 28F490211AAFBBC600C8E0CC /* DatesFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatesFormViewController.swift; sourceTree = ""; }; + 286067321AEDBD4A002F1E04 /* CustomRowsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CustomRowsViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 286067341AEDBD4A002F1E04 /* FloatLabeledTextFieldCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatLabeledTextFieldCell.swift; sourceTree = ""; }; + 286067391AEDBD4A002F1E04 /* XLFormRatingCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XLFormRatingCell.swift; sourceTree = ""; }; + 2860673A1AEDBD4A002F1E04 /* XLFormRatingCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = XLFormRatingCell.xib; sourceTree = ""; }; + 2860673C1AEDBD4A002F1E04 /* XLFormWeekDaysCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XLFormWeekDaysCell.swift; sourceTree = ""; }; + 2860673D1AEDBD4A002F1E04 /* XLFormWeekDaysCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = XLFormWeekDaysCell.xib; sourceTree = ""; }; + 286067451AEDC3D7002F1E04 /* XLRatingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XLRatingView.swift; sourceTree = ""; }; + 286E8B731AE809EF00F2767A /* DynamicSelectorsFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DynamicSelectorsFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 286E8B771AE80C4300F2767A /* UsersTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UsersTableViewController.swift; path = Examples/Selectors/DynamicSelector/UsersTableViewController.swift; sourceTree = SOURCE_ROOT; }; + 286E8B7C1AE86C8900F2767A /* XLFormCustomCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XLFormCustomCell.swift; sourceTree = ""; }; + 286E8B7D1AE86C8900F2767A /* OthersFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = OthersFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 286E8B811AE9286B00F2767A /* CustomSelectorsFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CustomSelectorsFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 286E8B831AE9286B00F2767A /* CLLocationValueTrasformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CLLocationValueTrasformer.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 286E8B841AE9286B00F2767A /* MapViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + 286E8B851AE9286B00F2767A /* MapViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MapViewController.xib; sourceTree = ""; }; + 286E8B8B1AE9993F00F2767A /* MultivaluedFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = MultivaluedFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 288646141AE59474007A8B9B /* ExamplesFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ExamplesFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 288646171AE5C7EA007A8B9B /* iPhoneStoryboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPhoneStoryboard.storyboard; sourceTree = ""; }; + 2886461A1AE5C958007A8B9B /* NativeEventFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = NativeEventFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 2886461E1AE5FEB5007A8B9B /* DateAndTimeValueTrasformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateAndTimeValueTrasformer.swift; sourceTree = ""; }; + 28B920741AE6F02F00BD6382 /* InputsFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; name = InputsFormViewController.swift; path = Examples/Inputs/InputsFormViewController.swift; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 28B920771AE73AA600BD6382 /* SelectorsFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorsFormViewController.swift; sourceTree = ""; }; + 28D832561AEBC4A7009E3B3F /* AccessoryViewFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AccessoryViewFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; + 28D832601AEBE4E4009E3B3F /* BasicPredicateViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BasicPredicateViewController.swift; sourceTree = ""; }; + 28D832661AEBEAA0009E3B3F /* BlogExampleViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlogExampleViewController.swift; path = Examples/PredicateExamples/BlogExampleViewController.swift; sourceTree = SOURCE_ROOT; }; + 28D832681AEBFE9F009E3B3F /* PredicateFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PredicateFormViewController.swift; path = Examples/PredicateExamples/PredicateFormViewController.swift; sourceTree = SOURCE_ROOT; }; + 28D8326B1AEC177E009E3B3F /* ValidationExamplesFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValidationExamplesFormViewController.swift; sourceTree = ""; }; + 28D8326E1AEC2D1B009E3B3F /* UICustomizationFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICustomizationFormViewController.swift; sourceTree = ""; }; + 28F490211AAFBBC600C8E0CC /* DatesFormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DatesFormViewController.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 2EB9C638FC2450A0B9786D1E /* Pods-SwiftExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftExample/Pods-SwiftExample.release.xcconfig"; sourceTree = ""; }; 420D9BAB7B0D2AF9487DD060 /* Pods-SwiftExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftExample/Pods-SwiftExample.debug.xcconfig"; sourceTree = ""; }; - 854F8DF43072D7C59CBECB68 /* libPods-SwiftExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 9CFB9BA3A82D5F6FE7CCE5A5 /* libPods-SwiftExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-SwiftExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -34,7 +86,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 2724071466166BFA1E54E659 /* libPods-SwiftExample.a in Frameworks */, + DD7B43598E698717584375E9 /* libPods-SwiftExample.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -62,11 +114,20 @@ 2847A6A01AAF2679000A2ABE /* SwiftExample */ = { isa = PBXGroup; children = ( + 286067311AEDBD4A002F1E04 /* CustomRows */, + 28D8326D1AEC2D1B009E3B3F /* UICustomization */, + 28D8326A1AEC177E009E3B3F /* Validations */, + 28D8325F1AEBE4E4009E3B3F /* PredicateExamples */, + 28D832551AEBC4A7009E3B3F /* AccessoryViews */, + 286E8B8A1AE9993F00F2767A /* MultiValuedSections */, + 286E8B7A1AE86C8900F2767A /* Others */, + 28B920761AE7378400BD6382 /* Selectors */, + 28B920711AE6EB6100BD6382 /* Inputs */, + 288646191AE5C958007A8B9B /* RealExamples */, + 288646161AE5C7EA007A8B9B /* StoryboardExample */, + 288646141AE59474007A8B9B /* ExamplesFormViewController.swift */, 28F490201AAFBBC600C8E0CC /* Dates */, 2847A6A31AAF2679000A2ABE /* AppDelegate.swift */, - 2847A6A71AAF2679000A2ABE /* Main.storyboard */, - 2847A6AA1AAF2679000A2ABE /* Images.xcassets */, - 2847A6AC1AAF2679000A2ABE /* LaunchScreen.xib */, 2847A6A11AAF2679000A2ABE /* Supporting Files */, ); path = SwiftExample; @@ -75,15 +136,185 @@ 2847A6A11AAF2679000A2ABE /* Supporting Files */ = { isa = PBXGroup; children = ( + 2847A6AA1AAF2679000A2ABE /* Images.xcassets */, 2847A6A21AAF2679000A2ABE /* Info.plist */, 2847A6C31AAF2B14000A2ABE /* SwiftExample-Bridging-Header.h */, ); name = "Supporting Files"; sourceTree = ""; }; + 286067311AEDBD4A002F1E04 /* CustomRows */ = { + isa = PBXGroup; + children = ( + 286067321AEDBD4A002F1E04 /* CustomRowsViewController.swift */, + 286067331AEDBD4A002F1E04 /* FloatLabeledTextField */, + 286067351AEDBD4A002F1E04 /* Rating */, + 2860673B1AEDBD4A002F1E04 /* Weekdays */, + ); + name = CustomRows; + path = Examples/CustomRows; + sourceTree = SOURCE_ROOT; + }; + 286067331AEDBD4A002F1E04 /* FloatLabeledTextField */ = { + isa = PBXGroup; + children = ( + 286067341AEDBD4A002F1E04 /* FloatLabeledTextFieldCell.swift */, + ); + path = FloatLabeledTextField; + sourceTree = ""; + }; + 286067351AEDBD4A002F1E04 /* Rating */ = { + isa = PBXGroup; + children = ( + 286067361AEDBD4A002F1E04 /* RatingView */, + 286067391AEDBD4A002F1E04 /* XLFormRatingCell.swift */, + 2860673A1AEDBD4A002F1E04 /* XLFormRatingCell.xib */, + ); + path = Rating; + sourceTree = ""; + }; + 286067361AEDBD4A002F1E04 /* RatingView */ = { + isa = PBXGroup; + children = ( + 286067451AEDC3D7002F1E04 /* XLRatingView.swift */, + ); + path = RatingView; + sourceTree = ""; + }; + 2860673B1AEDBD4A002F1E04 /* Weekdays */ = { + isa = PBXGroup; + children = ( + 2860673C1AEDBD4A002F1E04 /* XLFormWeekDaysCell.swift */, + 2860673D1AEDBD4A002F1E04 /* XLFormWeekDaysCell.xib */, + ); + path = Weekdays; + sourceTree = ""; + }; + 286E8B6C1AE8099F00F2767A /* DynamicSelector */ = { + isa = PBXGroup; + children = ( + 286E8B771AE80C4300F2767A /* UsersTableViewController.swift */, + 286E8B731AE809EF00F2767A /* DynamicSelectorsFormViewController.swift */, + ); + path = DynamicSelector; + sourceTree = ""; + }; + 286E8B7A1AE86C8900F2767A /* Others */ = { + isa = PBXGroup; + children = ( + 286E8B7B1AE86C8900F2767A /* CustomCells */, + 286E8B7D1AE86C8900F2767A /* OthersFormViewController.swift */, + ); + path = Others; + sourceTree = ""; + }; + 286E8B7B1AE86C8900F2767A /* CustomCells */ = { + isa = PBXGroup; + children = ( + 286E8B7C1AE86C8900F2767A /* XLFormCustomCell.swift */, + ); + path = CustomCells; + sourceTree = ""; + }; + 286E8B801AE9286B00F2767A /* CustomSelectors */ = { + isa = PBXGroup; + children = ( + 286E8B811AE9286B00F2767A /* CustomSelectorsFormViewController.swift */, + 286E8B821AE9286B00F2767A /* XLFormRowViewController */, + ); + path = CustomSelectors; + sourceTree = ""; + }; + 286E8B821AE9286B00F2767A /* XLFormRowViewController */ = { + isa = PBXGroup; + children = ( + 286E8B831AE9286B00F2767A /* CLLocationValueTrasformer.swift */, + 286E8B841AE9286B00F2767A /* MapViewController.swift */, + 286E8B851AE9286B00F2767A /* MapViewController.xib */, + ); + path = XLFormRowViewController; + sourceTree = ""; + }; + 286E8B8A1AE9993F00F2767A /* MultiValuedSections */ = { + isa = PBXGroup; + children = ( + 286E8B8B1AE9993F00F2767A /* MultivaluedFormViewController.swift */, + ); + path = MultiValuedSections; + sourceTree = ""; + }; + 288646161AE5C7EA007A8B9B /* StoryboardExample */ = { + isa = PBXGroup; + children = ( + 288646171AE5C7EA007A8B9B /* iPhoneStoryboard.storyboard */, + ); + path = StoryboardExample; + sourceTree = ""; + }; + 288646191AE5C958007A8B9B /* RealExamples */ = { + isa = PBXGroup; + children = ( + 2886461A1AE5C958007A8B9B /* NativeEventFormViewController.swift */, + ); + path = RealExamples; + sourceTree = ""; + }; + 28B920711AE6EB6100BD6382 /* Inputs */ = { + isa = PBXGroup; + children = ( + 28B920741AE6F02F00BD6382 /* InputsFormViewController.swift */, + ); + path = Inputs; + sourceTree = ""; + }; + 28B920761AE7378400BD6382 /* Selectors */ = { + isa = PBXGroup; + children = ( + 286E8B801AE9286B00F2767A /* CustomSelectors */, + 286E8B6C1AE8099F00F2767A /* DynamicSelector */, + 28B920771AE73AA600BD6382 /* SelectorsFormViewController.swift */, + ); + name = Selectors; + sourceTree = ""; + }; + 28D832551AEBC4A7009E3B3F /* AccessoryViews */ = { + isa = PBXGroup; + children = ( + 28D832561AEBC4A7009E3B3F /* AccessoryViewFormViewController.swift */, + ); + path = AccessoryViews; + sourceTree = ""; + }; + 28D8325F1AEBE4E4009E3B3F /* PredicateExamples */ = { + isa = PBXGroup; + children = ( + 28D832681AEBFE9F009E3B3F /* PredicateFormViewController.swift */, + 28D832601AEBE4E4009E3B3F /* BasicPredicateViewController.swift */, + 28D832661AEBEAA0009E3B3F /* BlogExampleViewController.swift */, + ); + path = PredicateExamples; + sourceTree = ""; + }; + 28D8326A1AEC177E009E3B3F /* Validations */ = { + isa = PBXGroup; + children = ( + 28D8326B1AEC177E009E3B3F /* ValidationExamplesFormViewController.swift */, + ); + path = Validations; + sourceTree = ""; + }; + 28D8326D1AEC2D1B009E3B3F /* UICustomization */ = { + isa = PBXGroup; + children = ( + 28D8326E1AEC2D1B009E3B3F /* UICustomizationFormViewController.swift */, + ); + path = UICustomization; + sourceTree = ""; + }; 28F490201AAFBBC600C8E0CC /* Dates */ = { isa = PBXGroup; children = ( + 2886461E1AE5FEB5007A8B9B /* DateAndTimeValueTrasformer.swift */, 28F490211AAFBBC600C8E0CC /* DatesFormViewController.swift */, ); name = Dates; @@ -93,7 +324,7 @@ 402AE3EC1FACD058DCF0A2D3 /* Frameworks */ = { isa = PBXGroup; children = ( - 854F8DF43072D7C59CBECB68 /* libPods-SwiftExample.a */, + 9CFB9BA3A82D5F6FE7CCE5A5 /* libPods-SwiftExample.a */, ); name = Frameworks; sourceTree = ""; @@ -166,8 +397,10 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2847A6A91AAF2679000A2ABE /* Main.storyboard in Resources */, - 2847A6AE1AAF2679000A2ABE /* LaunchScreen.xib in Resources */, + 288646181AE5C7EA007A8B9B /* iPhoneStoryboard.storyboard in Resources */, + 286E8B891AE9286B00F2767A /* MapViewController.xib in Resources */, + 286067441AEDBD4A002F1E04 /* XLFormWeekDaysCell.xib in Resources */, + 286067421AEDBD4A002F1E04 /* XLFormRatingCell.xib in Resources */, 2847A6AB1AAF2679000A2ABE /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -212,32 +445,37 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 28B920781AE73AA600BD6382 /* SelectorsFormViewController.swift in Sources */, + 28D832671AEBEAA0009E3B3F /* BlogExampleViewController.swift in Sources */, + 28D8326C1AEC177E009E3B3F /* ValidationExamplesFormViewController.swift in Sources */, + 286067411AEDBD4A002F1E04 /* XLFormRatingCell.swift in Sources */, 28F490221AAFBBC600C8E0CC /* DatesFormViewController.swift in Sources */, + 286E8B8C1AE9993F00F2767A /* MultivaluedFormViewController.swift in Sources */, + 28D8326F1AEC2D1B009E3B3F /* UICustomizationFormViewController.swift in Sources */, + 2860673E1AEDBD4A002F1E04 /* CustomRowsViewController.swift in Sources */, + 286E8B781AE80C4300F2767A /* UsersTableViewController.swift in Sources */, + 286067461AEDC3D7002F1E04 /* XLRatingView.swift in Sources */, + 288646151AE59474007A8B9B /* ExamplesFormViewController.swift in Sources */, + 286067431AEDBD4A002F1E04 /* XLFormWeekDaysCell.swift in Sources */, + 2860673F1AEDBD4A002F1E04 /* FloatLabeledTextFieldCell.swift in Sources */, + 286E8B7E1AE86C8900F2767A /* XLFormCustomCell.swift in Sources */, + 286E8B871AE9286B00F2767A /* CLLocationValueTrasformer.swift in Sources */, + 2886461C1AE5C958007A8B9B /* NativeEventFormViewController.swift in Sources */, + 286E8B7F1AE86C8900F2767A /* OthersFormViewController.swift in Sources */, 2847A6A41AAF2679000A2ABE /* AppDelegate.swift in Sources */, + 28D832691AEBFE9F009E3B3F /* PredicateFormViewController.swift in Sources */, + 28D832571AEBC4A7009E3B3F /* AccessoryViewFormViewController.swift in Sources */, + 286E8B861AE9286B00F2767A /* CustomSelectorsFormViewController.swift in Sources */, + 2886461F1AE5FEB5007A8B9B /* DateAndTimeValueTrasformer.swift in Sources */, + 28B920751AE6F02F00BD6382 /* InputsFormViewController.swift in Sources */, + 28D832631AEBE4E4009E3B3F /* BasicPredicateViewController.swift in Sources */, + 286E8B751AE809EF00F2767A /* DynamicSelectorsFormViewController.swift in Sources */, + 286E8B881AE9286B00F2767A /* MapViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 2847A6A71AAF2679000A2ABE /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 2847A6A81AAF2679000A2ABE /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 2847A6AC1AAF2679000A2ABE /* LaunchScreen.xib */ = { - isa = PBXVariantGroup; - children = ( - 2847A6AD1AAF2679000A2ABE /* Base */, - ); - name = LaunchScreen.xib; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - /* Begin XCBuildConfiguration section */ 2847A6BB1AAF2679000A2ABE /* Debug */ = { isa = XCBuildConfiguration; @@ -323,6 +561,7 @@ baseConfigurationReference = 420D9BAB7B0D2AF9487DD060 /* Pods-SwiftExample.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = SwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -335,6 +574,7 @@ baseConfigurationReference = 2EB9C638FC2450A0B9786D1E /* Pods-SwiftExample.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = SwiftExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Examples/Swift/SwiftExample/AccessoryViews/AccessoryViewFormViewController.swift b/Examples/Swift/SwiftExample/AccessoryViews/AccessoryViewFormViewController.swift new file mode 100644 index 0000000..9f1a439 --- /dev/null +++ b/Examples/Swift/SwiftExample/AccessoryViews/AccessoryViewFormViewController.swift @@ -0,0 +1,197 @@ +// +// AccessoryViewFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + + +class AccessoryViewFormViewController : XLFormViewController { + + + private enum Tags : String { + case AccessoryViewRowNavigationEnabled = "RowNavigationEnabled" + case AccessoryViewRowNavigationShowAccessoryView = "RowNavigationShowAccessoryView" + case AccessoryViewRowNavigationStopDisableRow = "rowNavigationStopDisableRow" + case AccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow = "rowNavigationSkipCanNotBecomeFirstResponderRow" + case AccessoryViewRowNavigationStopInlineRow = "rowNavigationStopInlineRow" + case AccessoryViewName = "name" + case AccessoryViewEmail = "email" + case AccessoryViewTwitter = "twitter" + case AccessoryViewUrl = "url" + case AccessoryViewDate = "date" + case AccessoryViewTextView = "textView" + case AccessoryViewCheck = "check" + case AccessoryViewNotes = "notes" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Accessory View") + form.rowNavigationOptions = XLFormRowNavigationOptions.Enabled + + // Configuration section + section = XLFormSectionDescriptor() + section.title = "Row Navigation Settings" + section.footerTitle = "Changing the Settings values you will navigate differently" + form.addFormSection(section) + + // RowNavigationEnabled + row = XLFormRowDescriptor(tag: Tags.AccessoryViewRowNavigationEnabled.rawValue, rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "Row Navigation Enabled?") + row.value = true + section.addFormRow(row) + + // RowNavigationShowAccessoryView + row = XLFormRowDescriptor(tag: Tags.AccessoryViewRowNavigationShowAccessoryView.rawValue, rowType:XLFormRowDescriptorTypeBooleanCheck, title:"Show input accessory row?") + row.value = (form.rowNavigationOptions & XLFormRowNavigationOptions.Enabled) == XLFormRowNavigationOptions.Enabled + row.hidden = "$\(Tags.AccessoryViewRowNavigationEnabled.rawValue) == 0" + section.addFormRow(row) + + // RowNavigationStopDisableRow + row = XLFormRowDescriptor(tag: Tags.AccessoryViewRowNavigationStopDisableRow.rawValue, rowType: XLFormRowDescriptorTypeBooleanCheck, title:"Stop when reach disabled row?") + row.value = (form.rowNavigationOptions & XLFormRowNavigationOptions.StopDisableRow) == XLFormRowNavigationOptions.StopDisableRow + row.hidden = "$\(Tags.AccessoryViewRowNavigationEnabled.rawValue) == 0" + section.addFormRow(row) + + // RowNavigationStopInlineRow + row = XLFormRowDescriptor(tag: Tags.AccessoryViewRowNavigationStopInlineRow.rawValue, rowType: XLFormRowDescriptorTypeBooleanCheck, title: "Stop when reach inline row?") + row.value = (form.rowNavigationOptions & XLFormRowNavigationOptions.StopInlineRow) == XLFormRowNavigationOptions.StopInlineRow + row.hidden = "$\(Tags.AccessoryViewRowNavigationEnabled.rawValue) == 0" + section.addFormRow(row) + + // RowNavigationSkipCanNotBecomeFirstResponderRow + row = XLFormRowDescriptor(tag: Tags.AccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow.rawValue, rowType:XLFormRowDescriptorTypeBooleanCheck, title:"Skip Can Not Become First Responder Row?") + row.value = (form.rowNavigationOptions & XLFormRowNavigationOptions.SkipCanNotBecomeFirstResponderRow) == XLFormRowNavigationOptions.SkipCanNotBecomeFirstResponderRow + row.hidden = "$\(Tags.AccessoryViewRowNavigationEnabled.rawValue) == 0" + section.addFormRow(row) + + + + section = XLFormSectionDescriptor() + form.addFormSection(section) + + + // Name + row = XLFormRowDescriptor(tag: Tags.AccessoryViewName.rawValue, rowType: XLFormRowDescriptorTypeText, title: "Name") + row.required = true + section.addFormRow(row) + + // Email + row = XLFormRowDescriptor(tag: Tags.AccessoryViewEmail.rawValue, rowType: XLFormRowDescriptorTypeEmail, title: "Email") + // validate the email + row.addValidator(XLFormValidator.emailValidator()) + section.addFormRow(row) + + // Twitter + row = XLFormRowDescriptor(tag: Tags.AccessoryViewTwitter.rawValue, rowType: XLFormRowDescriptorTypeTwitter, title: "Twitter") + row.disabled = NSNumber(bool: true) + row.value = "@no_editable" + section.addFormRow(row) + + // Url + row = XLFormRowDescriptor(tag: Tags.AccessoryViewUrl.rawValue, rowType: XLFormRowDescriptorTypeURL, title: "Url") + section.addFormRow(row) + + + // Date + row = XLFormRowDescriptor(tag: Tags.AccessoryViewDate.rawValue, rowType:XLFormRowDescriptorTypeDateInline, title:"Date Inline") + row.value = NSDate.new() + section.addFormRow(row) + + + + section = XLFormSectionDescriptor() + form.addFormSection(section) + + + + row = XLFormRowDescriptor(tag: Tags.AccessoryViewTextView.rawValue, rowType:XLFormRowDescriptorTypeTextView, title: nil) + row.cellConfigAtConfigure["textView.placeholder"] = "TEXT VIEW EXAMPLE" + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.AccessoryViewCheck.rawValue, rowType:XLFormRowDescriptorTypeBooleanCheck, title:"Ckeck") + section.addFormRow(row) + + section = XLFormSectionDescriptor() + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.AccessoryViewNotes.rawValue, rowType:XLFormRowDescriptorTypeTextView, title:"Notes") + section.addFormRow(row) + + self.form = form + } + + + override func inputAccessoryViewForRowDescriptor(rowDescriptor: XLFormRowDescriptor!) -> UIView! { + if self.form.formRowWithTag(Tags.AccessoryViewRowNavigationShowAccessoryView.rawValue)!.value!.boolValue == false { + return nil + } + return super.inputAccessoryViewForRowDescriptor(rowDescriptor) + } + + +//MARK: XLFormDescriptorDelegate + + override func formRowDescriptorValueHasChanged(formRow: XLFormRowDescriptor!, oldValue: AnyObject!, newValue: AnyObject!) { + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + if formRow.tag == Tags.AccessoryViewRowNavigationStopDisableRow.rawValue { + if formRow.value.boolValue == true { + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptions.StopDisableRow + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptions.StopDisableRow) + } + } + else if formRow.tag == Tags.AccessoryViewRowNavigationStopInlineRow.rawValue { + if formRow.value.boolValue == true { + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptions.StopInlineRow + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptions.StopInlineRow) + } + } + else if formRow.tag == Tags.AccessoryViewRowNavigationSkipCanNotBecomeFirstResponderRow.rawValue { + if formRow.value.boolValue == true { + self.form.rowNavigationOptions = self.form.rowNavigationOptions | XLFormRowNavigationOptions.SkipCanNotBecomeFirstResponderRow + } + else{ + self.form.rowNavigationOptions = self.form.rowNavigationOptions & (~XLFormRowNavigationOptions.SkipCanNotBecomeFirstResponderRow) + } + } + + } + +} diff --git a/Examples/Swift/SwiftExample/AppDelegate.swift b/Examples/Swift/SwiftExample/AppDelegate.swift index cd702c5..4c0c59b 100644 --- a/Examples/Swift/SwiftExample/AppDelegate.swift +++ b/Examples/Swift/SwiftExample/AppDelegate.swift @@ -3,7 +3,7 @@ // SwiftExample // // Created by Martin Barreto on 3/10/15. -// Copyright (c) 2015 Xmartlabs. All rights reserved. +// Copyright (c) 2014-2015 Xmartlabs. All rights reserved. // import UIKit @@ -15,7 +15,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + + // Declare custom rows + XLFormViewController.cellClassesForRowDescriptorTypes()[XLFormRowDescriptorTypeRate] = "XLFormRatingCell" + XLFormViewController.cellClassesForRowDescriptorTypes()[XLFormRowDescriptorTypeFloatLabeledTextField] = FloatLabeledTextFieldCell.self + XLFormViewController.cellClassesForRowDescriptorTypes()[XLFormRowDescriptorTypeWeekDays] = "XLFormWeekDaysCell" + // Override point for customization after application launch. + self.window = UIWindow.init(frame: UIScreen.mainScreen().bounds) + // Override point for customization after application launch. + self.window!.backgroundColor = UIColor.whiteColor() + + // load the initial form form Storybiard + let storyboard = UIStoryboard.init(name:"iPhoneStoryboard", bundle:nil) + self.window!.rootViewController = storyboard.instantiateInitialViewController() as? UIViewController + self.window!.makeKeyAndVisible() return true } @@ -30,7 +44,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func applicationWillEnterForeground(application: UIApplication) { - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + // Called as part of the transition from the background to the inactive state here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(application: UIApplication) { diff --git a/Examples/Swift/SwiftExample/Base.lproj/LaunchScreen.xib b/Examples/Swift/SwiftExample/Base.lproj/LaunchScreen.xib deleted file mode 100644 index 96ab0a2..0000000 --- a/Examples/Swift/SwiftExample/Base.lproj/LaunchScreen.xib +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Examples/Swift/SwiftExample/Base.lproj/Main.storyboard b/Examples/Swift/SwiftExample/Base.lproj/Main.storyboard deleted file mode 100644 index d8f926b..0000000 --- a/Examples/Swift/SwiftExample/Base.lproj/Main.storyboard +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Examples/Swift/SwiftExample/CustomRows/CustomRowsViewController.m b/Examples/Swift/SwiftExample/CustomRows/CustomRowsViewController.m new file mode 100644 index 0000000..a873738 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/CustomRowsViewController.m @@ -0,0 +1,109 @@ +// CustomRowsViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "CustomRowsViewController.h" +#import "XLForm.h" +#import "XLFormWeekDaysCell.h" +#import "XLFormRatingCell.h" +#import "FloatLabeledTextFieldCell.h" +#import "XLFormCustomCell.h" + +static NSString * const kCustomRowFirstRatingTag = @"CustomRowFirstRatingTag"; +static NSString * const kCustomRowSecondRatingTag = @"CustomRowSecondRatingTag"; +static NSString * const kCustomRowFloatLabeledTextFieldTag = @"CustomRowFloatLabeledTextFieldTag"; +static NSString * const kCustomRowWeekdays = @"CustomRowWeekdays"; +static NSString * const kCustomRowText = @"kCustomText"; + +@implementation CustomRowsViewController + +-(id)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + +-(void)initializeForm +{ + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Custom Rows"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Section Ratings + section = [XLFormSectionDescriptor formSectionWithTitle:@"Ratings"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowFirstRatingTag rowType:XLFormRowDescriptorTypeRate title:@"First Rating"]; + row.value = @(3); + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowSecondRatingTag rowType:XLFormRowDescriptorTypeRate title:@"Second Rating"]; + row.value = @(1); + [section addFormRow:row]; + + // Section Float Labeled Text Field + section = [XLFormSectionDescriptor formSectionWithTitle:@"Float Labeled Text Field"]; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowFloatLabeledTextFieldTag rowType:XLFormRowDescriptorTypeFloatLabeledTextField title:@"Title"]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowFloatLabeledTextFieldTag rowType:XLFormRowDescriptorTypeFloatLabeledTextField title:@"First Name"]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowFloatLabeledTextFieldTag rowType:XLFormRowDescriptorTypeFloatLabeledTextField title:@"Last Name"]; + [section addFormRow:row]; + + // Section Weekdays + section = [XLFormSectionDescriptor formSectionWithTitle:@"Weekdays"]; + [form addFormSection:section]; + + // WeekDays + row = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowWeekdays rowType:XLFormRowDescriptorTypeWeekDays]; + row.value = @{ + kSunday: @(NO), + kMonday: @(YES), + kTuesday: @(YES), + kWednesday: @(NO), + kThursday: @(NO), + kFriday: @(NO), + kSaturday: @(NO) + }; + [section addFormRow:row]; + + + section = [XLFormSectionDescriptor formSection]; + [form addFormSection:section]; + + XLFormRowDescriptor *customRowDescriptor = [XLFormRowDescriptor formRowDescriptorWithTag:kCustomRowText rowType:@"XLFormRowDescriptorTypeCustom"]; + // Must set custom cell or add custom cell to cellClassesForRowDescriptorTypes dictionary before XLFormViewController loaded + customRowDescriptor.cellClass = [XLFormCustomCell class]; + [section addFormRow:customRowDescriptor]; + + self.form = form; +} + +@end diff --git a/Examples/Swift/SwiftExample/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.m b/Examples/Swift/SwiftExample/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.m new file mode 100644 index 0000000..f1f2a6e --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/FloatLabeledTextField/FloatLabeledTextFieldCell.m @@ -0,0 +1,187 @@ +// FloatLabeledTextFieldCell.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "FloatLabeledTextFieldCell.h" +#import "UIView+XLFormAdditions.h" +#import "JVFloatLabeledTextField.h" +#import "NSObject+XLFormAdditions.h" + +#import + +NSString * const XLFormRowDescriptorTypeFloatLabeledTextField = @"XLFormRowDescriptorTypeFloatLabeledTextField"; + +const static CGFloat kHMargin = 15.0f; +const static CGFloat kVMargin = 8.0f; +const static CGFloat kFloatingLabelFontSize = 11.0f; + +@interface FloatLabeledTextFieldCell () +@property (nonatomic) JVFloatLabeledTextField * floatLabeledTextField; +@end + +@implementation FloatLabeledTextFieldCell + +@synthesize floatLabeledTextField =_floatLabeledTextField; + ++(void)load +{ + [XLFormViewController.cellClassesForRowDescriptorTypes setObject:[FloatLabeledTextFieldCell class] forKey:XLFormRowDescriptorTypeFloatLabeledTextField]; +} + +-(JVFloatLabeledTextField *)floatLabeledTextField +{ + if (_floatLabeledTextField) return _floatLabeledTextField; + + _floatLabeledTextField = [JVFloatLabeledTextField autolayoutView]; + _floatLabeledTextField.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody]; + _floatLabeledTextField.floatingLabel.font = [UIFont boldSystemFontOfSize:kFloatingLabelFontSize]; + + _floatLabeledTextField.clearButtonMode = UITextFieldViewModeWhileEditing; + return _floatLabeledTextField; +} + +#pragma mark - XLFormDescriptorCell + +-(void)configure +{ + [super configure]; + [self setSelectionStyle:UITableViewCellSelectionStyleNone]; + [self.contentView addSubview:self.floatLabeledTextField]; + [self.floatLabeledTextField setDelegate:self]; + [self.contentView addConstraints:[self layoutConstraints]]; +} + +-(void)update +{ + [super update]; + + self.floatLabeledTextField.attributedPlaceholder = + [[NSAttributedString alloc] initWithString:self.rowDescriptor.title + attributes:@{NSForegroundColorAttributeName: [UIColor lightGrayColor]}]; + + self.floatLabeledTextField.text = self.rowDescriptor.value ? [self.rowDescriptor.value displayText] : self.rowDescriptor.noValueDisplayText; + [self.floatLabeledTextField setEnabled:!self.rowDescriptor.isDisabled]; + + self.floatLabeledTextField.floatingLabelTextColor = [UIColor lightGrayColor]; + + [self.floatLabeledTextField setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; +} + +-(BOOL)formDescriptorCellCanBecomeFirstResponder +{ + return !self.rowDescriptor.isDisabled; +} + +-(BOOL)formDescriptorCellBecomeFirstResponder +{ + return [self.floatLabeledTextField becomeFirstResponder]; +} + +#pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldClear:(UITextField *)textField +{ + return [self.formViewController textFieldShouldClear:textField]; +} + +- (BOOL)textFieldShouldReturn:(UITextField *)textField +{ + return [self.formViewController textFieldShouldReturn:textField]; +} + +- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField +{ + return [self.formViewController textFieldShouldBeginEditing:textField]; +} + +- (BOOL)textFieldShouldEndEditing:(UITextField *)textField +{ + return [self.formViewController textFieldShouldEndEditing:textField]; +} + +- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { + return [self.formViewController textField:textField shouldChangeCharactersInRange:range replacementString:string]; +} + +- (void)textFieldDidBeginEditing:(UITextField *)textField +{ + [self.formViewController textFieldDidBeginEditing:textField]; +} + +- (void)textFieldDidEndEditing:(UITextField *)textField +{ + [self textFieldDidChange:textField]; + [self.formViewController textFieldDidEndEditing:textField]; +} + +-(void)setReturnKeyType:(UIReturnKeyType)returnKeyType +{ + self.floatLabeledTextField.returnKeyType = returnKeyType; +} + +-(UIReturnKeyType)returnKeyType +{ + return self.floatLabeledTextField.returnKeyType; +} + ++(CGFloat)formDescriptorCellHeightForRowDescriptor:(XLFormRowDescriptor *)rowDescriptor { + return 55; +} + + + +-(NSArray *)layoutConstraints +{ + NSMutableArray * result = [[NSMutableArray alloc] init]; + + NSDictionary * views = @{@"floatLabeledTextField": self.floatLabeledTextField}; + NSDictionary *metrics = @{@"hMargin":@(kHMargin), + @"vMargin":@(kVMargin)}; + + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(hMargin)-[floatLabeledTextField]-(hMargin)-|" + options:0 + metrics:metrics + views:views]]; + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(vMargin)-[floatLabeledTextField]-(vMargin)-|" + options:0 + metrics:metrics + views:views]]; + return result; +} + +#pragma mark - Helpers + +- (void)textFieldDidChange:(UITextField *)textField +{ + if (self.floatLabeledTextField == textField) { + if ([self.floatLabeledTextField.text length] > 0) { + self.rowDescriptor.value = self.floatLabeledTextField.text; + } else { + self.rowDescriptor.value = nil; + } + } +} + + + +@end diff --git a/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.h b/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.h new file mode 100644 index 0000000..630f8ce --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.h @@ -0,0 +1,29 @@ +// XLRatingView.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@interface XLRatingView : AXRatingView + +@end diff --git a/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.m b/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.m new file mode 100644 index 0000000..6f35279 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Rating/RatingView/XLRatingView.m @@ -0,0 +1,69 @@ +// XLRatingView.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLRatingView.h" + +@implementation XLRatingView + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self customize]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + [self customize]; + } + return self; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + self = [super initWithCoder:aDecoder]; + if (self) { + [self customize]; + } + return self; +} + +- (void)customize +{ + UIColor * grayColor = [UIColor colorWithRed:(205/255.0) green:(201/255.0) blue:(201/255.0) alpha:1]; + self.baseColor = grayColor; + + UIColor * goldColor = [UIColor colorWithRed:(255/255.0) green:(215/255.0) blue:0 alpha:1]; + self.highlightColor = goldColor; + self.markFont = [UIFont systemFontOfSize:23.0f]; + self.translatesAutoresizingMaskIntoConstraints = NO; + self.stepInterval = 1.0f; +} + +@end + diff --git a/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.m b/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.m new file mode 100644 index 0000000..ac4f148 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.m @@ -0,0 +1,62 @@ +// XLFormRatingCell.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLFormRatingCell.h" + +NSString * const XLFormRowDescriptorTypeRate = @"XLFormRowDescriptorTypeRate"; + +@implementation XLFormRatingCell + ++(void)load +{ + [XLFormViewController.cellClassesForRowDescriptorTypes setObject:NSStringFromClass([XLFormRatingCell class]) forKey:XLFormRowDescriptorTypeRate]; +} + +- (void)configure +{ + [super configure]; + + self.selectionStyle = UITableViewCellSelectionStyleNone; + [self.ratingView addTarget:self action:@selector(rateChanged:) forControlEvents:UIControlEventValueChanged]; +} + +- (void)update +{ + [super update]; + + self.ratingView.value = [self.rowDescriptor.value floatValue]; + self.rateTitle.text = self.rowDescriptor.title; + + [self.ratingView setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.rateTitle setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; +} + +#pragma mark - Events + +-(void)rateChanged:(AXRatingView *)ratingView +{ + self.rowDescriptor.value = [NSNumber numberWithFloat:ratingView.value]; +} + +@end diff --git a/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.xib b/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.xib new file mode 100644 index 0000000..4e0f654 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Rating/XLFormRatingCell.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.m b/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.m new file mode 100644 index 0000000..52c9795 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.m @@ -0,0 +1,154 @@ +// XLFormWeekDaysCell.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLFormWeekDaysCell.h" + +NSString * const XLFormRowDescriptorTypeWeekDays = @"XLFormRowDescriptorTypeWeekDays"; + +NSString *const kSunday= @"sunday"; +NSString *const kMonday = @"monday"; +NSString *const kTuesday = @"tuesday"; +NSString *const kWednesday = @"wednesday"; +NSString *const kThursday = @"thursday"; +NSString *const kFriday = @"friday"; +NSString *const kSaturday = @"saturday"; + +@interface XLFormWeekDaysCell() +@property (weak, nonatomic) IBOutlet UIButton *sundayButton; +@property (weak, nonatomic) IBOutlet UIButton *mondayButton; +@property (weak, nonatomic) IBOutlet UIButton *tuesdayButton; +@property (weak, nonatomic) IBOutlet UIButton *wednesdayButton; +@property (weak, nonatomic) IBOutlet UIButton *thursdayButton; +@property (weak, nonatomic) IBOutlet UIButton *fridayButton; +@property (weak, nonatomic) IBOutlet UIButton *saturdayButton; +@end + +@implementation XLFormWeekDaysCell + ++(void)load +{ + [XLFormViewController.cellClassesForRowDescriptorTypes setObject:NSStringFromClass([XLFormWeekDaysCell class]) forKey:XLFormRowDescriptorTypeWeekDays]; +} + +#pragma mark - XLFormDescriptorCell + +- (void)configure +{ + [super configure]; + + self.selectionStyle = UITableViewCellSelectionStyleNone; + [self configureButtons]; +} + +-(void)update +{ + [super update]; + [self updateButtons]; +} + +#pragma mark - Action + +- (IBAction)dayTapped:(id)sender { + [self dayTapped:sender day:[self getDayFormButton:sender]]; +} + +#pragma mark - Helpers + +-(void)configureButtons +{ + for (UIView *subview in self.contentView.subviews) + { + if ([subview isKindOfClass:[UIButton class]]) + { + UIButton * button = (UIButton *)subview; + [button setImage:[UIImage imageNamed:@"uncheckedDay"] forState:UIControlStateNormal]; + [button setImage:[UIImage imageNamed:@"checkedDay"] forState:UIControlStateSelected]; + button.adjustsImageWhenHighlighted = NO; + [self imageTopTitleBottom:button]; + } + } +} + +-(void)updateButtons +{ + NSDictionary * value = self.rowDescriptor.value; + self.sundayButton.selected = [[value objectForKey:kSunday] boolValue]; + self.mondayButton.selected = [[value objectForKey:kMonday] boolValue]; + self.tuesdayButton.selected = [[value objectForKey:kTuesday] boolValue]; + self.wednesdayButton.selected = [[value objectForKey:kWednesday] boolValue]; + self.thursdayButton.selected = [[value objectForKey:kThursday] boolValue]; + self.fridayButton.selected = [[value objectForKey:kFriday] boolValue]; + self.saturdayButton.selected = [[value objectForKey:kSaturday] boolValue]; + + [self.sundayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.mondayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.tuesdayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.wednesdayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.thursdayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.fridayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; + [self.saturdayButton setAlpha:((self.rowDescriptor.isDisabled) ? .6 : 1)]; +} + +-(NSString *)getDayFormButton:(id)sender +{ + if (sender == self.sundayButton) return kSunday; + if (sender == self.mondayButton) return kMonday; + if (sender == self.tuesdayButton) return kTuesday; + if (sender == self.wednesdayButton) return kWednesday; + if (sender == self.thursdayButton) return kThursday; + if (sender == self.fridayButton) return kFriday; + return kSaturday; +} + +-(void)dayTapped:(UIButton *)button day:(NSString *)day +{ + button.selected = !button.selected; + NSMutableDictionary * value = [self.rowDescriptor.value mutableCopy]; + [value setObject:@(button.selected) forKey:day]; + self.rowDescriptor.value = value; +} + +-(void)imageTopTitleBottom:(UIButton *)button +{ + // the space between the image and text + CGFloat spacing = 3.0; + + // lower the text and push it left so it appears centered + // below the image + CGSize imageSize = button.imageView.image.size; + button.titleEdgeInsets = UIEdgeInsetsMake(0.0, - imageSize.width, - (imageSize.height + spacing), 0.0); + + // raise the image and push it right so it appears centered + // above the text + CGSize titleSize = [button.titleLabel.text sizeWithAttributes:@{NSFontAttributeName: button.titleLabel.font}]; + button.imageEdgeInsets = UIEdgeInsetsMake(- (titleSize.height + spacing), 0.0, 0.0, - titleSize.width); +} + ++(CGFloat)formDescriptorCellHeightForRowDescriptor:(XLFormRowDescriptor *)rowDescriptor +{ + return 60; +} + + +@end diff --git a/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.xib b/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.xib new file mode 100644 index 0000000..3da9f86 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomRows/Weekdays/XLFormWeekDaysCell.xib @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/SwiftExample/CustomSelectors/CustomSelectorsFormViewController.swift b/Examples/Swift/SwiftExample/CustomSelectors/CustomSelectorsFormViewController.swift new file mode 100644 index 0000000..83818f0 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomSelectors/CustomSelectorsFormViewController.swift @@ -0,0 +1,75 @@ +// +// CustomSelectorsFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import MapKit + + +class CustomSelectorsFormViewController : XLFormViewController { + + private enum Tags : String { + case SelectorMap = "selectorMap" + case SelectorMapPopover = "selectorMapPopover" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Custom Selectors") + + section = XLFormSectionDescriptor.formSectionWithTitle("TextField Types") + section.footerTitle = "CustomSelectorsFormViewController.swift" + form.addFormSection(section) + + // Selector Push + row = XLFormRowDescriptor(tag: Tags.SelectorMap.rawValue, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Coordinate") + row.action.viewControllerClass = MapViewController.self + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad { + // Selector PopOver + row = XLFormRowDescriptor(tag: Tags.SelectorMapPopover.rawValue, rowType: XLFormRowDescriptorTypeSelectorPopover, title: "Coordinate PopOver") + row.action.viewControllerClass = MapViewController.self + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + } + self.form = form + } +} diff --git a/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift new file mode 100644 index 0000000..948d3d6 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/CLLocationValueTrasformer.swift @@ -0,0 +1,49 @@ +// +// CLLocationValueTrasformer.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +import MapKit + +class CLLocationValueTrasformer : NSValueTransformer { + + override class func transformedValueClass() -> AnyClass { + return NSString.self + } + + + override class func allowsReverseTransformation() -> Bool { + return false + } + + + override func transformedValue(value: AnyObject?) -> AnyObject? { + if let valueData: AnyObject = value { + let location = valueData as! CLLocation + return String(format: "%0.4f, %0.4f", location.coordinate.latitude, location.coordinate.longitude) + } + return nil + } + +} diff --git a/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.swift b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.swift new file mode 100644 index 0000000..1cf6bbc --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.swift @@ -0,0 +1,99 @@ +// +// MapViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import MapKit + +class MapAnnotation : NSObject, MKAnnotation { + + @objc var coordinate : CLLocationCoordinate2D + + override init() { + self.coordinate = CLLocationCoordinate2D(latitude: -33.0, longitude: -56.0) + super.init() + } +} + +@objc(MapViewController) +class MapViewController : UIViewController, XLFormRowDescriptorViewController, MKMapViewDelegate { + + var rowDescriptor: XLFormRowDescriptor? + lazy var mapView : MKMapView = { + let mapView = MKMapView(frame: self.view.frame) + mapView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight + return mapView + }() + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + required init(coder aDecoder: NSCoder) { + + super.init(coder: aDecoder) + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + self.view.addSubview(self.mapView) + self.mapView.delegate = self + if let rowDesc = self.rowDescriptor { + if rowDesc.value != nil { + let coordinate = (self.rowDescriptor!.value as! CLLocation).coordinate + self.mapView.setCenterCoordinate(coordinate, animated: false) + self.title = String(format: "%0.4f, %0.4f", self.mapView.centerCoordinate.latitude, self.mapView.centerCoordinate.longitude) + let annotation = MapAnnotation() + annotation.coordinate = coordinate + self.mapView.addAnnotation(annotation) + } + } + } + + +//MARK - - MKMapViewDelegate + + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + + let pinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "annotation") + pinAnnotationView.pinColor = MKPinAnnotationColor.Red + pinAnnotationView.draggable = true + pinAnnotationView.animatesDrop = true + return pinAnnotationView + } + + + func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) { + if (newState == MKAnnotationViewDragState.Ending){ + self.rowDescriptor!.value = CLLocation(latitude:view.annotation.coordinate.latitude, longitude:view.annotation.coordinate.longitude) + self.title = String(format: "%0.4f, %0.4f", view.annotation.coordinate.latitude, view.annotation.coordinate.longitude) + } + } + +} + + + + diff --git a/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.xib b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.xib new file mode 100644 index 0000000..b2815d1 --- /dev/null +++ b/Examples/Swift/SwiftExample/CustomSelectors/XLFormRowViewController/MapViewController.xib @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.h b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.h new file mode 100644 index 0000000..9334035 --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.h @@ -0,0 +1,31 @@ +// +// DynamicSelectorsFormViewController.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLForm.h" +#import "XLFormViewController.h" + +@interface DynamicSelectorsFormViewController : XLFormViewController + +@end diff --git a/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.m b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.m new file mode 100644 index 0000000..565ea7b --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.m @@ -0,0 +1,66 @@ +// +// DynamicSelectorsFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UsersTableViewController.h" +#import "DynamicSelectorsFormViewController.h" + +NSString *const kSelectorUser = @"selectorUser"; +NSString *const kSelectorUserPopover = @"kSelectorUserPopover"; + +@implementation DynamicSelectorsFormViewController + + +-(id)init +{ + self = [super init]; + if (self) { + XLFormDescriptor * form = [XLFormDescriptor formDescriptorWithTitle:@"Selectors"]; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + // Basic Information + section = [XLFormSectionDescriptor formSectionWithTitle:@"Dynamic Selectors"]; + section.footerTitle = @"DynamicSelectorsFormViewController.h"; + [form addFormSection:section]; + + + // Selector Push + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorUser rowType:XLFormRowDescriptorTypeSelectorPush title:@"User"]; + row.action.viewControllerClass = [UsersTableViewController class]; + [section addFormRow:row]; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){ + // Selector PopOver + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSelectorUserPopover rowType:XLFormRowDescriptorTypeSelectorPopover title:@"User Popover"]; + row.action.viewControllerClass = [UsersTableViewController class]; + [section addFormRow:row]; + } + self.form = form; + } + return self; +} + + +@end diff --git a/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.swift b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.swift new file mode 100644 index 0000000..caa4ca3 --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/DynamicSelectorsFormViewController.swift @@ -0,0 +1,63 @@ +// +// DynamicSelectorsFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +class DynamicSelectorsFormViewController : XLFormViewController { + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + let form = XLFormDescriptor(title: "Selectors") + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // Basic Information + section = XLFormSectionDescriptor.formSectionWithTitle("Dynamic Selectors") + section.footerTitle = "DynamicSelectorsFormViewController.swift" + form.addFormSection(section) + + // Selector Push + row = XLFormRowDescriptor(tag: "selectorUser", rowType:XLFormRowDescriptorTypeSelectorPush, title:"User") + row.action.viewControllerClass = UsersTableViewController.self + section.addFormRow(row) + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad { + // Selector PopOver + row = XLFormRowDescriptor(tag: "selectorUserPopover", rowType:XLFormRowDescriptorTypeSelectorPopover, title:"User Popover") + row.action.viewControllerClass = UsersTableViewController.self + section.addFormRow(row) + } + self.form = form + } + +} diff --git a/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.h b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.h new file mode 100644 index 0000000..6a9111b --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.h @@ -0,0 +1,31 @@ +// +// UsersTableViewController.h +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "XLFormRowDescriptor.h" +#import "XLTableViewController.h" + +@interface UsersTableViewController : XLTableViewController + +@end diff --git a/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.m b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.m new file mode 100644 index 0000000..bbc6455 --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.m @@ -0,0 +1,245 @@ +// +// UsersTableViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UsersTableViewController.h" +#import "UserLocalDataLoader.h" +#import "UserRemoteDataLoader.h" +#import "User+Additions.h" + +// AFNetworking +#import + + +@interface UserCell : UITableViewCell + +@property (nonatomic) UIImageView * userImage; +@property (nonatomic) UILabel * userName; + +@end + +@implementation UserCell + +@synthesize userImage = _userImage; +@synthesize userName = _userName; + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + + [self.contentView addSubview:self.userImage]; + [self.contentView addSubview:self.userName]; + + [self.contentView addConstraints:[self layoutConstraints]]; + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + + +#pragma mark - Views + +-(UIImageView *)userImage +{ + if (_userImage) return _userImage; + _userImage = [UIImageView new]; + [_userImage setTranslatesAutoresizingMaskIntoConstraints:NO]; + _userImage.layer.masksToBounds = YES; + _userImage.layer.cornerRadius = 10.0f; + return _userImage; +} + +-(UILabel *)userName +{ + if (_userName) return _userName; + _userName = [UILabel new]; + [_userName setTranslatesAutoresizingMaskIntoConstraints:NO]; + _userName.font = [UIFont fontWithName:@"HelveticaNeue" size:15.f]; + + return _userName; +} + +#pragma mark - Layout Constraints + +-(NSArray *)layoutConstraints{ + + NSMutableArray * result = [NSMutableArray array]; + + NSDictionary * views = @{ @"image": self.userImage, + @"name": self.userName}; + + + NSDictionary *metrics = @{@"imgSize":@50.0, + @"margin" :@12.0}; + + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(margin)-[image(imgSize)]-[name]" + options:NSLayoutFormatAlignAllTop + metrics:metrics + views:views]]; + + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(margin)-[image(imgSize)]" + options:0 + metrics:metrics + views:views]]; + return result; +} + + +@end + + +@interface UsersTableViewController () + +@end + +@implementation UsersTableViewController + +@synthesize rowDescriptor = _rowDescriptor; +@synthesize popoverController = __popoverController; + +static NSString *const kCellIdentifier = @"CellIdentifier"; + + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + [self initialize]; + } + return self; +} + +-(void)initialize +{ + // Enable the pagination + self.loadingPagingEnabled = YES; + + // Support Search Controller + self.supportSearchController = YES; + + [self setLocalDataLoader:[[UserLocalDataLoader alloc] init]]; + [self setRemoteDataLoader:[[UserRemoteDataLoader alloc] init]]; + + // Search + [self setSearchLocalDataLoader:[[UserLocalDataLoader alloc] init]]; + [self setSearchRemoteDataLoader:[[UserRemoteDataLoader alloc] init]]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + // SearchBar + self.tableView.tableHeaderView = self.searchDisplayController.searchBar; + + // register cells + [self.searchDisplayController.searchResultsTableView registerClass:[UserCell class] forCellReuseIdentifier:kCellIdentifier]; + [self.tableView registerClass:[UserCell class] forCellReuseIdentifier:kCellIdentifier]; + + [self customizeAppearance]; +} + +#pragma mark - UITableViewDataSource + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UserCell *cell = (UserCell *) [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];; + + User * user = nil; + if (tableView == self.tableView){ + user = (User *)[self.localDataLoader objectAtIndexPath:indexPath]; + } + else{ + user = (User *)[self.searchLocalDataLoader objectAtIndexPath:indexPath]; + } + + cell.userName.text = user.userName; + NSMutableURLRequest* imageRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:user.userImageURL]]; + [imageRequest setValue:@"image/*" forHTTPHeaderField:@"Accept"]; + __typeof__(cell) __weak weakCell = cell; + [cell.userImage setImageWithURLRequest: imageRequest + placeholderImage:[User defaultProfileImage] + success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { + if (image) { + [weakCell.userImage setImage:image]; + } + } + failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { + }]; + cell.accessoryType = [[self.rowDescriptor.value formValue] isEqual:user.userId] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; + return cell; +} + +- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 73.0f; +} + + +#pragma mark - UITableViewDelegate + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + User * user = nil; + if (tableView == self.tableView){ + user = (User *)[self.localDataLoader objectAtIndexPath:indexPath]; + } + else{ + user = (User *)[self.searchLocalDataLoader objectAtIndexPath:indexPath]; + } + self.rowDescriptor.value = user; + + if (self.popoverController){ + [self.popoverController dismissPopoverAnimated:YES]; + [self.popoverController.delegate popoverControllerDidDismissPopover:self.popoverController]; + } + else if ([self.parentViewController isKindOfClass:[UINavigationController class]]){ + [self.navigationController popViewControllerAnimated:YES]; + } +} + + +#pragma mark - Helpers + +-(void)customizeAppearance +{ + [[self navigationItem] setTitle:@"Select a User"]; + + [self.tableView setBackgroundColor:[UIColor colorWithWhite:0.9 alpha:1.0]]; + [self.tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]]; + + [self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor colorWithWhite:0.9 alpha:1.0]]; + [self.searchDisplayController.searchResultsTableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]]; +} + + +@end diff --git a/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.swift b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.swift new file mode 100644 index 0000000..bbc6455 --- /dev/null +++ b/Examples/Swift/SwiftExample/DynamicSelector/UsersTableViewController.swift @@ -0,0 +1,245 @@ +// +// UsersTableViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "UsersTableViewController.h" +#import "UserLocalDataLoader.h" +#import "UserRemoteDataLoader.h" +#import "User+Additions.h" + +// AFNetworking +#import + + +@interface UserCell : UITableViewCell + +@property (nonatomic) UIImageView * userImage; +@property (nonatomic) UILabel * userName; + +@end + +@implementation UserCell + +@synthesize userImage = _userImage; +@synthesize userName = _userName; + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + + [self.contentView addSubview:self.userImage]; + [self.contentView addSubview:self.userName]; + + [self.contentView addConstraints:[self layoutConstraints]]; + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + + +#pragma mark - Views + +-(UIImageView *)userImage +{ + if (_userImage) return _userImage; + _userImage = [UIImageView new]; + [_userImage setTranslatesAutoresizingMaskIntoConstraints:NO]; + _userImage.layer.masksToBounds = YES; + _userImage.layer.cornerRadius = 10.0f; + return _userImage; +} + +-(UILabel *)userName +{ + if (_userName) return _userName; + _userName = [UILabel new]; + [_userName setTranslatesAutoresizingMaskIntoConstraints:NO]; + _userName.font = [UIFont fontWithName:@"HelveticaNeue" size:15.f]; + + return _userName; +} + +#pragma mark - Layout Constraints + +-(NSArray *)layoutConstraints{ + + NSMutableArray * result = [NSMutableArray array]; + + NSDictionary * views = @{ @"image": self.userImage, + @"name": self.userName}; + + + NSDictionary *metrics = @{@"imgSize":@50.0, + @"margin" :@12.0}; + + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(margin)-[image(imgSize)]-[name]" + options:NSLayoutFormatAlignAllTop + metrics:metrics + views:views]]; + + [result addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(margin)-[image(imgSize)]" + options:0 + metrics:metrics + views:views]]; + return result; +} + + +@end + + +@interface UsersTableViewController () + +@end + +@implementation UsersTableViewController + +@synthesize rowDescriptor = _rowDescriptor; +@synthesize popoverController = __popoverController; + +static NSString *const kCellIdentifier = @"CellIdentifier"; + + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + [self initialize]; + } + return self; +} + +-(void)initialize +{ + // Enable the pagination + self.loadingPagingEnabled = YES; + + // Support Search Controller + self.supportSearchController = YES; + + [self setLocalDataLoader:[[UserLocalDataLoader alloc] init]]; + [self setRemoteDataLoader:[[UserRemoteDataLoader alloc] init]]; + + // Search + [self setSearchLocalDataLoader:[[UserLocalDataLoader alloc] init]]; + [self setSearchRemoteDataLoader:[[UserRemoteDataLoader alloc] init]]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + // SearchBar + self.tableView.tableHeaderView = self.searchDisplayController.searchBar; + + // register cells + [self.searchDisplayController.searchResultsTableView registerClass:[UserCell class] forCellReuseIdentifier:kCellIdentifier]; + [self.tableView registerClass:[UserCell class] forCellReuseIdentifier:kCellIdentifier]; + + [self customizeAppearance]; +} + +#pragma mark - UITableViewDataSource + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UserCell *cell = (UserCell *) [tableView dequeueReusableCellWithIdentifier:kCellIdentifier forIndexPath:indexPath];; + + User * user = nil; + if (tableView == self.tableView){ + user = (User *)[self.localDataLoader objectAtIndexPath:indexPath]; + } + else{ + user = (User *)[self.searchLocalDataLoader objectAtIndexPath:indexPath]; + } + + cell.userName.text = user.userName; + NSMutableURLRequest* imageRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:user.userImageURL]]; + [imageRequest setValue:@"image/*" forHTTPHeaderField:@"Accept"]; + __typeof__(cell) __weak weakCell = cell; + [cell.userImage setImageWithURLRequest: imageRequest + placeholderImage:[User defaultProfileImage] + success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { + if (image) { + [weakCell.userImage setImage:image]; + } + } + failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) { + }]; + cell.accessoryType = [[self.rowDescriptor.value formValue] isEqual:user.userId] ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; + return cell; +} + +- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath +{ + return 73.0f; +} + + +#pragma mark - UITableViewDelegate + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + User * user = nil; + if (tableView == self.tableView){ + user = (User *)[self.localDataLoader objectAtIndexPath:indexPath]; + } + else{ + user = (User *)[self.searchLocalDataLoader objectAtIndexPath:indexPath]; + } + self.rowDescriptor.value = user; + + if (self.popoverController){ + [self.popoverController dismissPopoverAnimated:YES]; + [self.popoverController.delegate popoverControllerDidDismissPopover:self.popoverController]; + } + else if ([self.parentViewController isKindOfClass:[UINavigationController class]]){ + [self.navigationController popViewControllerAnimated:YES]; + } +} + + +#pragma mark - Helpers + +-(void)customizeAppearance +{ + [[self navigationItem] setTitle:@"Select a User"]; + + [self.tableView setBackgroundColor:[UIColor colorWithWhite:0.9 alpha:1.0]]; + [self.tableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]]; + + [self.searchDisplayController.searchResultsTableView setBackgroundColor:[UIColor colorWithWhite:0.9 alpha:1.0]]; + [self.searchDisplayController.searchResultsTableView setTableFooterView:[[UIView alloc] initWithFrame:CGRectZero]]; +} + + +@end diff --git a/Examples/Swift/SwiftExample/ExamplesFormViewController.swift b/Examples/Swift/SwiftExample/ExamplesFormViewController.swift new file mode 100644 index 0000000..5625c34 --- /dev/null +++ b/Examples/Swift/SwiftExample/ExamplesFormViewController.swift @@ -0,0 +1,177 @@ +// +// ExamplesFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + + + +class ExamplesFormViewController : XLFormViewController { + + private enum Tags : String { + case RealExample = "RealExamples" + case TextFieldAndTextView = "TextFieldAndTextView" + case Selectors = "Selectors" + case Othes = "Others" + case Dates = "Dates" + case Predicates = "BasicPredicates" + case BlogExample = "BlogPredicates" + case Multivalued = "Multivalued" + case MultivaluedOnlyReorder = "MultivaluedOnlyReorder" + case MultivaluedOnlyInsert = "MultivaluedOnlyInsert" + case MultivaluedOnlyDelete = "MultivaluedOnlyDelete" + case Validations = "Validations" + case UICusomization = "Customization" + case Custom = "Custom" + case AccessoryView = "Accessory View" + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + +// MARK: Helpers + + func initializeForm() { + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row: XLFormRowDescriptor + + form = XLFormDescriptor() + + section = XLFormSectionDescriptor.formSectionWithTitle("Real examples") + form.addFormSection(section) + + // NativeEventFormViewController + row = XLFormRowDescriptor(tag: Tags.RealExample.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "iOS Calendar Event Form") + row.action.formSegueIdenfifier = "NativeEventNavigationViewControllerSegue" + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSectionWithTitle("This form is actually an example") + section.footerTitle = "ExamplesFormViewController.swift, Select an option to view another example" + form.addFormSection(section) + + + // TextFieldAndTextView + row = XLFormRowDescriptor(tag: Tags.TextFieldAndTextView.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Text Fields") + row.action.viewControllerClass = InputsFormViewController.self + section.addFormRow(row) + + + // Selectors + row = XLFormRowDescriptor(tag: Tags.Selectors.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Selectors") + row.action.formSegueIdenfifier = "SelectorsFormViewControllerSegue" + section.addFormRow(row) + + + // Dates + row = XLFormRowDescriptor(tag: Tags.Dates.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Date & Time") + row.action.viewControllerClass = DatesFormViewController.self + section.addFormRow(row) + + // Others + row = XLFormRowDescriptor(tag: Tags.Othes.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Other Rows") + row.action.formSegueIdenfifier = "OthersFormViewControllerSegue" + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Multivalued example") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.Multivalued.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Multivalued Sections") + row.action.viewControllerClass = MultivaluedFormViewController.self + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.MultivaluedOnlyReorder.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Multivalued Only Reorder") + row.action.viewControllerClass = MultivaluedOnlyReorderViewController.self + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.MultivaluedOnlyInsert.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Multivalued Only Insert") + row.action.viewControllerClass = MultivaluedOnlyInserViewController.self + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.MultivaluedOnlyDelete.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Multivalued Only Delete") + row.action.viewControllerClass = MultivaluedOnlyDeleteViewController.self + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("UI Customization") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.UICusomization.rawValue, rowType: XLFormRowDescriptorTypeButton, title:"UI Customization") + row.action.viewControllerClass = UICustomizationFormViewController.self + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSectionWithTitle("Custom Rows") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.Custom.rawValue, rowType: XLFormRowDescriptorTypeButton, title:"Custom Rows") + row.action.viewControllerClass = CustomRowsViewController.self + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSectionWithTitle("Accessory View") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.AccessoryView.rawValue, rowType: XLFormRowDescriptorTypeButton, title:"Accessory Views") + row.action.viewControllerClass = AccessoryViewFormViewController.self + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Validation Examples") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.Validations.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Validation Examples") + row.action.formSegueIdenfifier = "ValidationExamplesFormViewControllerSegue" + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSectionWithTitle("Using Predicates") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: Tags.Predicates.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Very basic predicates") + row.action.formSegueIdenfifier = "BasicPredicateViewControllerSegue" + section.addFormRow(row) + + + row = XLFormRowDescriptor(tag: Tags.Predicates.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Blog Example Hide predicates") + row.action.formSegueIdenfifier = "BlogExampleViewSegue" + section.addFormRow(row) + + + row = XLFormRowDescriptor(tag: Tags.Predicates.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Another example") + row.action.formSegueIdenfifier = "PredicateFormViewControllerSegue" + section.addFormRow(row) + + self.form = form + } +} diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/Contents.json index 36d2c80..8ec97a8 100644 --- a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,28 +1,33 @@ { "images" : [ { - "idiom" : "iphone", "size" : "29x29", + "idiom" : "iphone", + "filename" : "xl_appicon_58.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "29x29", + "idiom" : "iphone", + "filename" : "xl_appicon_87.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "xl_appicon_80-1.png", "scale" : "2x" }, { - "idiom" : "iphone", "size" : "40x40", + "idiom" : "iphone", + "filename" : "xl_appicon_120-1.png", "scale" : "3x" }, { - "idiom" : "iphone", "size" : "60x60", + "idiom" : "iphone", + "filename" : "xl_appicon_120.png", "scale" : "2x" }, { @@ -51,13 +56,15 @@ "scale" : "2x" }, { - "idiom" : "ipad", "size" : "76x76", + "idiom" : "ipad", + "filename" : "xl_appicon_76.png", "scale" : "1x" }, { - "idiom" : "ipad", "size" : "76x76", + "idiom" : "ipad", + "filename" : "xl_appicon_152.png", "scale" : "2x" } ], diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120-1.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a9712a512580260c65e70e38c8e551d365cf0c60 GIT binary patch literal 1509 zcmVpMhw=#6Sud8mj+Wf)GyC^HmrUL=j3EkAo0S)rof)KKw-}#RQC);f+fv z7I#CGB0C9-YKVv6rUIRW)vt_0H0A*Uh;c-uSQb3V6&eo5ahMHP0b~fC#*(&B%!Wvl zoCb;VC0r?52E(3W;idu^$XRa4r&xdhBF)`2bjYaDG%*^OK(Us`khJT-hn_DM7S(M%)F}+J*lNOhY85j_Qva||mVCSG-280;EGjI!Dlh7F! zJk9Xo4+EYyJgq_+=t^L0Lfi`M;NTilg@i8L#gI8BG#Ar5BLc%1=!gl=p-u-T7+lVU z3=B}wxs+za!UrIPD>0Cfz35tc(9^k8a5UQ7IUSr!k)!cASAd1#y(uE~<1b<8lo8Pi z4a_k(V74QsgrP}yYri&uVxO4AfE*#1>hYJ;K+glqO41w+%v-=5hPAw-R*X~M(W9-r zQAdwDdeqUQjvjS1xd0#l`}T5zKn#QdSj3xP4|bqdU`uvn36@|5A~xXO1rfo6;K3}B zn9Xy{W6a^70`zm4OtNMMn+woD0}V9LKm!dl&_DwXbd_MbM?9~-lMH(7uAjEcw$S>2 z>~_e;!n*0Po(=A@GQ~`9dhH+M;?G#00B#5!&Whyem|AF2D=2wf+f79;rhUf=y;f9p zPbfKH2c=f%Gf3i<$2SY;`=X!62g9-HsMSqA@7s$sif@E5Wko`Zw<9~mabER4($7`S zuAb=64&@$hY=H(EXrO@x8fc(_1{&z*<1IjYcZ?E2425xg3t?LoEQPhTun;_eC-4eh z!5erKZ=$`RTiLp{HiDpF=L->;oyjCKNhX_L#VFi%;`P_! z^2K)NZM{%#d5^q|szWZIYZ};SQ;46>)E)$*vJf9Us?C{c{=dzrywfd*qi~l?oUV=z zcY!!Rv}GBnCgMC*hqHnBoip0eOCCQqqJ4XaY3Q1ZbdvCO`vCfCd_90yNMBXrO^6K$o0fm=RR$5AxGH00000 LNkvXXu0mjff@8Wv literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_120.png new file mode 100644 index 0000000000000000000000000000000000000000..a9712a512580260c65e70e38c8e551d365cf0c60 GIT binary patch literal 1509 zcmVpMhw=#6Sud8mj+Wf)GyC^HmrUL=j3EkAo0S)rof)KKw-}#RQC);f+fv z7I#CGB0C9-YKVv6rUIRW)vt_0H0A*Uh;c-uSQb3V6&eo5ahMHP0b~fC#*(&B%!Wvl zoCb;VC0r?52E(3W;idu^$XRa4r&xdhBF)`2bjYaDG%*^OK(Us`khJT-hn_DM7S(M%)F}+J*lNOhY85j_Qva||mVCSG-280;EGjI!Dlh7F! zJk9Xo4+EYyJgq_+=t^L0Lfi`M;NTilg@i8L#gI8BG#Ar5BLc%1=!gl=p-u-T7+lVU z3=B}wxs+za!UrIPD>0Cfz35tc(9^k8a5UQ7IUSr!k)!cASAd1#y(uE~<1b<8lo8Pi z4a_k(V74QsgrP}yYri&uVxO4AfE*#1>hYJ;K+glqO41w+%v-=5hPAw-R*X~M(W9-r zQAdwDdeqUQjvjS1xd0#l`}T5zKn#QdSj3xP4|bqdU`uvn36@|5A~xXO1rfo6;K3}B zn9Xy{W6a^70`zm4OtNMMn+woD0}V9LKm!dl&_DwXbd_MbM?9~-lMH(7uAjEcw$S>2 z>~_e;!n*0Po(=A@GQ~`9dhH+M;?G#00B#5!&Whyem|AF2D=2wf+f79;rhUf=y;f9p zPbfKH2c=f%Gf3i<$2SY;`=X!62g9-HsMSqA@7s$sif@E5Wko`Zw<9~mabER4($7`S zuAb=64&@$hY=H(EXrO@x8fc(_1{&z*<1IjYcZ?E2425xg3t?LoEQPhTun;_eC-4eh z!5erKZ=$`RTiLp{HiDpF=L->;oyjCKNhX_L#VFi%;`P_! z^2K)NZM{%#d5^q|szWZIYZ};SQ;46>)E)$*vJf9Us?C{c{=dzrywfd*qi~l?oUV=z zcY!!Rv}GBnCgMC*hqHnBoip0eOCCQqqJ4XaY3Q1ZbdvCO`vCfCd_90yNMBXrO^6K$o0fm=RR$5AxGH00000 LNkvXXu0mjff@8Wv literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_152.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_152.png new file mode 100644 index 0000000000000000000000000000000000000000..bdaf0545c05eefdba1d017f243a0e6e1bc13f061 GIT binary patch literal 1895 zcmZ9NX*3(?7sew(6Je^cl#U^GDpbc(Z7fL|OQicVf^R-@iV&~002Nmj*AD7LzOtXlngX>2(0u#cqBk|5!(471?NI|Gm@vbD; za1WgY)FElt3Lj0WeFno@AwtNYvbypnCl)AlMXE)!6ow(<^-P#%`&}D9`aM(W=t+d7 z-}VEPcWi@HNA{!$R&us-Ty5n;QrciE1_S`ZIhVZvQb?bf@=S?R=?VZ59oIf4?=ll^ z%g-ae^vp#Z2kOTaRgp#4QOT(m_^QYFi!P~)66Oebb&U!)$-1j<4T9EE={LL6GJvw; zB3BIO)t3g{?tko)^-x3sf|n#tpoHUr<#8vzOIu05%?;zNbs1|V`}+sb;!9vCgpEjo zwbTP^CT3Lb7CIIL;k1|1og=0Ppwr2hB5~DJRL-iUtx=d~r)Cw4F<@(+W9_#u!7UG5 zJUz^XJa07RD~{~0UkD+4gfLTP;D6^k3PlBJ*tdcR{po2*`6`c>f&z4wH-j!)&IL!% zEWRWcun70=@H)NRVLR{SuW^V`UvHA@3QBBNGvJX4Cd6MNvqa z?0K4&X5BqdGY|C-H9wJ>j_!B|2|XSpuNJyutla7b%X|?Y`RuBXZJP-Wf#ip>o%gQ6 zV?Z#oe=*dQxID)i>N(YBM!tU@Lzu)p`MZeKHM{e&t@5Au17Qj$lR2GpaWi%dV&65j z=e&uj{X|u6C=z1N=qFk+vx_NxWfZYCE^W%QlBjN<%j?^rt{}sP_l$)k zrc#@tB8Uwiz5EH+QV^+B7NH5hRN39*)H?5}^-}}y%iPmtndQYBgNrS-50f&$V#N~` z8rmeDomI&wB}8;^H)-x#UE76sn>|l?Aqo@}@CUZ#m*oNBq;w`qkk4=IQS5k8v;PD} zSU>uM2v9u@wz@pIEW|C~P-|hI+GwHg{_p>(z4iOfvoZKrptsJNLHZ?N} z{P<^K3jYy(joD!*AFmbK=nrmK$Kj=W*X85`msd9^ruCZVx80s4NVRP3=#;49AO%K; z2HkxD_lDx?q@I3~gia+YXGXIPmG^HrIc!ko_g5{x2)1mTN#4=WVI-NLxkJWK`5#j<+!RY(yb6g4BkaaiP>{mX}5}`=s<&!RZ**-mm#z^OQxv z@BaE{()zx8A?@OUoe7&d3<=817TO6rA5ve9okw2KoxABMQ_WtdXzXQ*{T9T|yZvW7 zb?)#bF*NSe%4BfP%Ic75o@V54#FHuF`RU&{zF$=HTcX}ON=^Os2Aol#Tvs{3^`+uo zocMnSk3F3ZTsDo~_@-3q3KyITA!E?!7vmV4Dm65Ep|fEb62|xFsj`YeOjukPa2+(9 z2}Pr6i?Oi;^k5$JHAzaP=vL07-s#0dN{|_6@e0S2nN4U-n`W6uE1+QTm}5XFAhRC; zDjX@G0uRhggXdpW-&5fS>GmEd=PM_9c3IYj9n>5ouY?$L+f{c-)d6BU)pc8M2M+u= zFZcti6S3c&nuf)l@ywdih)Z7stC^(UY*r=vZMcBZ^k=>`MAevlSC9u29I2Ze_bR8c zRL9Rh7lKhq@aImin?w$MbfEr;tff5gUbBs#SL%}_(>A5tiVEtV$Z%4cf{34()C;-d zpMKslRuSrP#)Hc=0;;kYT@PQhZmXT9D#~8juF%0V2&X)Y_Gpajm`=grRJ2~TaIlPk zS(fK7U%OQA?5}^Z{7?o1Z(+}dFomJifi~hW6{xDOX1}sLR9h0K*+Q9mK6d!vBzZfU zOzWWt&q~8O$1Y>C!p*>In;1C8`y81t`m7yF;hT z94WIO4U!D`5AnoXi>c}m23_Jw?8Wz?K8im=@ZTgHh2SU&X#mJEaM7S6)Kkv2*PqhQ T7}19xElB{**a};Naf$sOi&|** literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_58.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_58.png new file mode 100644 index 0000000000000000000000000000000000000000..43bf6f20647fbabeae454ee982b1f0ddae93a62b GIT binary patch literal 808 zcmV+@1K0eCP)p8*?SV!#22lMrBG_-~0J0Tli42cd|OdX@tO5O$-ONH7E{3UoEx;W*W@ zKrKB^wrv0bgwyM!d7H56_ofIo#Ba#nLsu<$8mbN$Q$XLLc@UvGL6l*?HbNaRQsJfo z#es2*fZHb?q7S z0Mfjz=8QMqYHp&B5Un2?!X(HKQKI%7r z3Agp>t=r?89%hen+`dNN9>hfGW+JmYgpO*58s(J7cM+b*T7y$fAn#&7XmP&QJt0)w mAq=fAuO?jK3Rk$o?TiPZR7GfKGSEr@0000C#5QQ<|d}62BjvZR2H60wP9djX7F@z45_%4lw$F1KBIX; z(gE%j+JEm0wQTTaR+Z>~eBtc@_Nl=(>`BfH%DT2}0uDcT(v>bpJbE&LnIo1@g5&wu z4JRF$j(!ko@>RBHU=e6^P`5w8?x7ylrQ)UT!W@;Pxa>Zrq6XusE7OKjdysNYg$d|i!)aBj#hqIa$F7&m2|7-t8^-ig)oW_Cmbz5HA zfZPan?3y(!92*!luDQGH=&LHaGI{YlnXgY)sJq)*zB(D`4;D&coYuHCu2J@M)L!oU zC*pe@qy4Qu7_JFtHJ#^vS23@lD6No85MqVs;{r?ygJHUjJUa^75ASt84G zZ*ih6=a+l+-YfVOH)d6IE_4vuB_z0SN6m^Vq1E3N1aEwhIMwzfw5n?AoQqZqi-$*rm@C#reYBaT#gf6a#LtPDJKj*I!gsn&=K223X3A>s4|+eSV{L1m yA0Xmi!)GcPuEH!j`Qgcnh1a2e#p3-htPJy)dCbg{3EB$GFbtlqelF{r5}E)rWN(=O literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_80-1.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_80-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7e3ffc806ead35d2db7dfe478b8fd787ed8773ab GIT binary patch literal 931 zcmV;U16=%xP)p8+>uV!#WiCH>zLokWplJPr~Ck~nokR3HOJT6zp1fEWiwsJ%Bukl39D zloLFSTQ^V+pKfZq93X%Q7*3JdG}O$3DTEfT$Vm?^m15Bh)Co_qAO0XTpe0~@&Ia1= zc$H{p!wp8Z4eknLH49!dB;FaqQ3Vh{L)6)$nz5yRpa=vJ){IvCLlQPxPQ>SIxPHuP zhA2N{t)Ph2jJ5hAN;BL}g8H!(2FR`jviEC4ixf-+qq&NnngIfcqR<{NSC3jeYB7n8 zC^7)B-6McxlHnzW3tuVDPLKi**fv6ID&vxch!8C73Humg1f-6`v;dcbs20@7KA_M_ za^jdOR+45huDB%I5m*uzS`vjfyh%!2XaF;vk5&?+7LQs?H2@GmquFWH;!%r7EgrRa z)M8q8Vfqyq3M3I+V51J$w4>C=4t$_iqX9Qg1@l!5ib=3ofgMDi*TZfc(AES| zXzLZvXdF2fFL(_?SnWo(m0;hHoWzxQ2aDYl+DdGyhT9EHM^v$uoTd+cTZ!x(lbnyK z;#ZO_rlPGRSd3;XWPpIkEK9z{n102T$EayB))2;;$0$nGKvRHb5!16qb`zedIb5B3 zbRXwS5^F26zwrYBmeDTEsKuiek6Jux@u1`r);n`;~!2Mz3y-iX84PFmp^~`}!DBDuVNDEZ=FqKQ`#5*8o zO?VFVPvHZESAkB4`xYn#EP(`1Q(@9*fMb|iIh=Me%ra=bI+Pk7coHx~>b?=xs+j?f zVf?WQ^dv+U*ibpIH!yL|M2A>KZY=@xA$;CZfCc33_oj4>?a_t@23W7o5FkX9S(G;| zF}*}^HySe7@QxwyCdD2GCcOE|1pExNsqqQ literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_87.png b/Examples/Swift/SwiftExample/Images.xcassets/AppIcon.appiconset/xl_appicon_87.png new file mode 100644 index 0000000000000000000000000000000000000000..5f0c9d273911c23f0dbdb4f6eddf18b4282399f0 GIT binary patch literal 1100 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 Z|34i-Debvr_C^2z002ovPDHLkV1n<>EUf?l literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Bart_Simpsons.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Bart_Simpsons.imageset/Contents.json new file mode 100644 index 0000000..6f27ef7 --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Bart_Simpsons.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Bart_Simpsons.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Contents.json new file mode 100644 index 0000000..3689187 --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Homer_Simpsons.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Homer_Simpsons.png b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Homer_Simpsons.imageset/Homer_Simpsons.png new file mode 100644 index 0000000000000000000000000000000000000000..194d9f6f6fb19aecb5cd82db1f577d93eb063971 GIT binary patch literal 11157 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 literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Contents.json new file mode 100644 index 0000000..9d697ff --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Lisa_Simpsons.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Lisa_Simpsons.png b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Lisa_Simpsons.imageset/Lisa_Simpsons.png new file mode 100644 index 0000000000000000000000000000000000000000..da566b8955234eed37f91748ecf2fc0933a9931d GIT binary patch literal 13369 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 Hu0mjfS`06_ literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Contents.json new file mode 100644 index 0000000..d9f5573 --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Marge_Simpsons.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Marge_Simpsons.png b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Marge_Simpsons.imageset/Marge_Simpsons.png new file mode 100644 index 0000000000000000000000000000000000000000..a4dd75e0909761e8db8426737290e9527fc74e75 GIT binary patch literal 11250 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 literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Contents.json new file mode 100644 index 0000000..e35f8ab --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Montgomery_Burns.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Montgomery_Burns.png b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Montgomery_Burns.imageset/Montgomery_Burns.png new file mode 100644 index 0000000000000000000000000000000000000000..6ae434450c179d980afa319e268fe6f044ad8ee4 GIT binary patch literal 10788 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 literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Contents.json b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Contents.json new file mode 100644 index 0000000..8c56cf6 --- /dev/null +++ b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "Otto_Mann.png" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Otto_Mann.png b/Examples/Swift/SwiftExample/Images.xcassets/Simpsons/Otto_Mann.imageset/Otto_Mann.png new file mode 100644 index 0000000000000000000000000000000000000000..e82bf1c20ee0e2dd3a30f94249b0b2472662ea58 GIT binary patch literal 13021 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

5X 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%0Di*uBQPX`EnJwNZJga`vB3UeeRg0DP2 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

bcZV{bh?jj467^Nn( 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 literal 0 HcmV?d00001 diff --git a/Examples/Swift/SwiftExample/Info.plist b/Examples/Swift/SwiftExample/Info.plist index 83e1abe..e3864b0 100644 --- a/Examples/Swift/SwiftExample/Info.plist +++ b/Examples/Swift/SwiftExample/Info.plist @@ -22,10 +22,8 @@ 1 LSRequiresIPhoneOS - UILaunchStoryboardName - LaunchScreen UIMainStoryboardFile - Main + iPhoneStoryboard UIRequiredDeviceCapabilities armv7 diff --git a/Examples/Swift/SwiftExample/Inputs/InputsFormViewController.swift b/Examples/Swift/SwiftExample/Inputs/InputsFormViewController.swift new file mode 100644 index 0000000..eb92568 --- /dev/null +++ b/Examples/Swift/SwiftExample/Inputs/InputsFormViewController.swift @@ -0,0 +1,157 @@ +// +// InputsFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class InputsFormViewController : XLFormViewController { + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + + form = XLFormDescriptor.formDescriptorWithTitle("Text Fields") as! XLFormDescriptor; + form.assignFirstResponderOnShow = true; + + section = XLFormSectionDescriptor.formSection () as! XLFormSectionDescriptor + form.addFormSection(section); + + // Title + row = XLFormRowDescriptor.formRowDescriptorWithTag("title", rowType: XLFormRowDescriptorTypeText) as! XLFormRowDescriptor + row.cellConfigAtConfigure["textField.placeholder"] = "Title" + row.required = true + section.addFormRow(row) + + // Location + row = XLFormRowDescriptor.formRowDescriptorWithTag("location", rowType: XLFormRowDescriptorTypeText) as! XLFormRowDescriptor + row.cellConfigAtConfigure["textField.placeholder"] = "Location" + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() as! XLFormSectionDescriptor + form.addFormSection(section) + + // All-day + row = XLFormRowDescriptor.formRowDescriptorWithTag("all-day", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "All-day") as! XLFormRowDescriptor + section.addFormRow(row) + + // Starts + row = XLFormRowDescriptor.formRowDescriptorWithTag("starts", rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Starts") as! XLFormRowDescriptor + row.value = NSDate(timeIntervalSinceNow: 60*60*24) + section.addFormRow(row) + + // Ends + row = XLFormRowDescriptor.formRowDescriptorWithTag("ends", rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Ends") as! XLFormRowDescriptor + row.value = NSDate(timeIntervalSinceNow: 60*60*25) + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() as! XLFormSectionDescriptor + form.addFormSection(section) + + // Repeat + row = XLFormRowDescriptor.formRowDescriptorWithTag("repeat", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Repeat") as! XLFormRowDescriptor + row.value = XLFormOptionsObject(value: 0, displayText: "Never") + row.selectorTitle = "Repeat" + row.selectorOptions = [XLFormOptionsObject(value: 0, displayText: "Never"), + XLFormOptionsObject(value: 1, displayText: "Every Day"), + XLFormOptionsObject(value: 2, displayText: "Every Week"), + XLFormOptionsObject(value: 3, displayText: "Every 2 Weeks"), + XLFormOptionsObject(value: 4, displayText: "Every Month"), + XLFormOptionsObject(value: 5, displayText: "Every Year")] + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() as! XLFormSectionDescriptor + form.addFormSection(section) + + // Alert + row = XLFormRowDescriptor.formRowDescriptorWithTag("alert", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Alert") as! XLFormRowDescriptor + row.value = XLFormOptionsObject(value: 0, displayText: "None") + row.selectorTitle = "Event Alert" + row.selectorOptions = [ + XLFormOptionsObject(value: 0, displayText: "None"), + XLFormOptionsObject(value: 1, displayText: "At time of event"), + XLFormOptionsObject(value: 2, displayText: "5 minutes before"), + XLFormOptionsObject(value: 3, displayText: "15 minutes before"), + XLFormOptionsObject(value: 4, displayText: "30 minutes before"), + XLFormOptionsObject(value: 5, displayText: "1 hour before"), + XLFormOptionsObject(value: 6, displayText: "2 hours before"), + XLFormOptionsObject(value: 7, displayText: "1 day before"), + XLFormOptionsObject(value: 8, displayText: "2 days before")] + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSection() as! XLFormSectionDescriptor + form.addFormSection(section) + + // Show As + row = XLFormRowDescriptor.formRowDescriptorWithTag("showAs", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Show As") as! XLFormRowDescriptor + row.value = XLFormOptionsObject(value: 0, displayText: "Busy") + row.selectorTitle = "Show As" + row.selectorOptions = [XLFormOptionsObject(value: 0, displayText:"Busy"), + XLFormOptionsObject(value: 1, displayText:"Free")] + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() as! XLFormSectionDescriptor + form.addFormSection(section) + + // URL + row = XLFormRowDescriptor.formRowDescriptorWithTag("url", rowType:XLFormRowDescriptorTypeURL) as! XLFormRowDescriptor + row.cellConfigAtConfigure["textField.placeholder"] = "URL" + section.addFormRow(row) + + // Notes + row = XLFormRowDescriptor.formRowDescriptorWithTag("notes", rowType:XLFormRowDescriptorTypeTextView) as! XLFormRowDescriptor + row.cellConfigAtConfigure["textView.placeholder"] = "Notes" + section.addFormRow(row) + + self.form = form; + } + + + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Save, target: self, action: "savePressed:") + } + + + func savePressed(button: UIBarButtonItem){ + let validationErrors : Array = self.formValidationErrors() as! Array + if (validationErrors.count > 0){ + self.showFormValidationError(validationErrors.first); + return; + } + self.tableView.endEditing(true) + // let alertView = UIAlertView( alloc] initWithTitle:NSLocalizedString(@"Valid Form", nil) message:@"No errors found" delegate:self cancelButtonTitle:NSLocalizedString(@"OK", nil) otherButtonTitles:nil]; + // [alertView show]; + } + +} diff --git a/Examples/Swift/SwiftExample/MultiValuedSections/MultivaluedFormViewController.swift b/Examples/Swift/SwiftExample/MultiValuedSections/MultivaluedFormViewController.swift new file mode 100644 index 0000000..5458968 --- /dev/null +++ b/Examples/Swift/SwiftExample/MultiValuedSections/MultivaluedFormViewController.swift @@ -0,0 +1,300 @@ +// +// MultiValuedFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class MultivaluedFormViewController : XLFormViewController { + + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Multivalued Examples") + + // Multivalued section + section = XLFormSectionDescriptor.formSectionWithTitle("Multivalued TextField", sectionOptions:XLFormSectionOptions.CanReorder | XLFormSectionOptions.CanInsert | XLFormSectionOptions.CanDelete, sectionInsertMode:XLFormSectionInsertMode.Button) + section.multivaluedAddButton.title = "Add New Tag" + section.footerTitle = "XLFormSectionInsertModeButton sectionType adds a 'Add Item' (Add New Tag) button row as last cell." + // set up the row template + row = XLFormRowDescriptor(tag: nil, rowType: XLFormRowDescriptorTypeName) + row.cellConfigAtConfigure["textField.placeholder"] = "Tag Name" + section.multivaluedRowTemplate = row + + form.addFormSection(section) + + + + + + // Another Multivalued section + section = XLFormSectionDescriptor.formSectionWithTitle("Multivalued ActionSheet Selector example", sectionOptions:XLFormSectionOptions.CanInsert | XLFormSectionOptions.CanDelete) + section.footerTitle = "XLFormSectionInsertModeLastRow sectionType adds a '+' icon inside last table view cell allowing us to add a new row." + form.addFormSection(section) + row = XLFormRowDescriptor(tag: nil, rowType: XLFormRowDescriptorTypeSelectorActionSheet, title: "Tap to select..") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + section.addFormRow(row) + + + // Another one + section = XLFormSectionDescriptor.formSectionWithTitle("Multivalued Push Selector example", sectionOptions:XLFormSectionOptions.CanInsert | XLFormSectionOptions.CanDelete | XLFormSectionOptions.CanReorder, sectionInsertMode:XLFormSectionInsertMode.Button) + section.footerTitle = "MultivaluedFormViewController.swift" + form.addFormSection(section) + row = XLFormRowDescriptor(tag: nil, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Tap to select )..") + row.selectorOptions = ["Option 1", "Option 2", "Option 3"] + section.multivaluedRowTemplate = row.copy() as! XLFormRowDescriptor + section.addFormRow(row) + + self.form = form + } + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Edit, target: self, action: "addDidTouch:") + } + +//MARK: - Actions + + func addDidTouch(sender: UIBarButtonItem) { + let actionSheet = UIActionSheet(title: nil, delegate: self, cancelButtonTitle: "Cancel", destructiveButtonTitle: "Remove Last Section", otherButtonTitles: "Add a section at the end", self.form!.disabled ? "Enable Form" : "Disable Form") + actionSheet.showInView(self.view) + } + +//MARK: - UIActionSheetDelegate + + + override func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) { + if actionSheet.destructiveButtonIndex == buttonIndex { + if self.form.formSections.count > 0 { + // remove last section + self.form.removeFormSectionAtIndex(UInt(self.form.formSections.count - 1)) + } + } + else if actionSheet.buttonTitleAtIndex(buttonIndex) == "Add a section at the end" { + // add a new section +// let dateString = NSDateFormatter.localizedStringFromDate(NSDate.new(), dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.ShortStyle) + let newSection = XLFormSectionDescriptor.formSectionWithTitle("Section created at \(NSDateFormatter.localizedStringFromDate(NSDate.new(), dateStyle: NSDateFormatterStyle.ShortStyle, timeStyle: NSDateFormatterStyle.ShortStyle))", sectionOptions:XLFormSectionOptions.CanInsert | XLFormSectionOptions.CanDelete) + newSection.multivaluedTag = "multivaluedPushSelector_\(self.form.formSections.count)" + let newRow = XLFormRowDescriptor(tag: nil, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Tap to select )..") + newRow.selectorOptions = ["Option 1", "Option 2", "Option 3"] + newSection.addFormRow(newRow) + self.form.addFormSection(newSection) + } + else { + self.form.disabled = !self.form.disabled + self.tableView.endEditing(true) + self.tableView.reloadData() + } + } +} + + + + +class MultivaluedOnlyReorderViewController : XLFormViewController { + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + func initializeForm() { + + let secondsPerDay = 24 * 60 * 60 + let list = ["Today", "Yesterday", "Before Yesterday"] + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Only Reorder Examples") + + // Multivalued Section with inline rows - section set up to support only reordering + section = XLFormSectionDescriptor.formSectionWithTitle("Reordering Inline Rows", + sectionOptions:XLFormSectionOptions.CanReorder) + section.footerTitle = "XLFormRowDescriptorTypeDateInline row type" + form.addFormSection(section) + var idx = 0 + for listItem in list { + let timeIntervalSinceNow : NSTimeInterval = NSTimeInterval(secondsPerDay * ++idx) + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeDateInline, title: listItem) + row.value = NSDate(timeIntervalSinceNow:timeIntervalSinceNow) + section.addFormRow(row) + } + + // Multivalued Section with common rows - section set up to support only reordering + section = XLFormSectionDescriptor.formSectionWithTitle("Reordering Rows", sectionOptions:XLFormSectionOptions.CanReorder) + section.footerTitle = "XLFormRowDescriptorTypeInfo row type" + form.addFormSection(section) + + + idx = 0 + for listItem in list { + let timeIntervalSinceNow : NSTimeInterval = NSTimeInterval(secondsPerDay * ++idx) + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeInfo, title: listItem) + row.value = NSDateFormatter.localizedStringFromDate(NSDate(timeIntervalSinceNow:timeIntervalSinceNow), dateStyle: NSDateFormatterStyle.MediumStyle, timeStyle: NSDateFormatterStyle.NoStyle) + section.addFormRow(row) + } + + self.form = form + } + +} + +class MultivaluedOnlyInserViewController : XLFormViewController { + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + func initializeForm() { + + let nameList = ["family", "male", "female", "client"] + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Multivalued Only Insert") + + section = XLFormSectionDescriptor.formSectionWithTitle("XLFormSectionInsertModeButton", sectionOptions:XLFormSectionOptions.CanInsert, sectionInsertMode:XLFormSectionInsertMode.Button) + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeText) + row.cellConfig["textField.placeholder"] = "Add a new tag" + section.multivaluedRowTemplate = row + + section = XLFormSectionDescriptor.formSectionWithTitle("XLFormSectionInsertModeButton With Inline Cells", sectionOptions:XLFormSectionOptions.CanInsert, sectionInsertMode:XLFormSectionInsertMode.Button) + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeDateInline) + row.value = NSDate.new() + row.title = "Date" + section.multivaluedRowTemplate = row + form.addFormSection(section) + + section = XLFormSectionDescriptor.formSectionWithTitle("XLFormSectionInsertModeLastRow", + sectionOptions:XLFormSectionOptions.CanInsert, sectionInsertMode:XLFormSectionInsertMode.LastRow) + form.addFormSection(section) + for tag in nameList { + // add a row to the section, the row will be used to crete new rows. + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeText) + row.cellConfig["textField.placeholder"] = "Add a new tag" + row.value = tag + section.addFormRow(row) + } + self.form = form + } +} + + +class MultivaluedOnlyDeleteViewController : XLFormViewController { + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Editing", style: UIBarButtonItemStyle.Plain, target: self, action: "toggleEditing:") + } + + func toggleEditing(sender : UIBarButtonItem) { + self.tableView.setEditing(!self.tableView.editing, animated: true) + sender.title = self.tableView.editing ? "Editing" : "Not Editing" + } + + func initializeForm() { + + let nameList = ["family", "male", "female", "client"] + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Multivalued Only Delete") + + section = XLFormSectionDescriptor.formSectionWithTitle(nil, sectionOptions:XLFormSectionOptions.CanDelete) + section.footerTitle = "you can swipe to delete when table.editing = NO (Not Editing)" + form.addFormSection(section) + + + for tag in nameList { + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeText) + row.cellConfig["textField.placeholder"] = "Add a new tag" + row.value = tag + section.addFormRow(row) + } + + // Multivalued Section with inline row. + section = XLFormSectionDescriptor.formSectionWithTitle(nil, sectionOptions:XLFormSectionOptions.CanDelete) + section.footerTitle = "you can swipe to delete when table.editing = NO (Not Editing)" + form.addFormSection(section) + + for _ in 1...4 { + row = XLFormRowDescriptor(tag: nil, rowType:XLFormRowDescriptorTypeSelectorPickerViewInline) + row.title = "Tap to select" + row.value = "client" + row.selectorOptions = nameList + section.addFormRow(row) + } + + self.form = form + } + + +} + diff --git a/Examples/Swift/SwiftExample/Others/CustomCells/XLFormCustomCell.swift b/Examples/Swift/SwiftExample/Others/CustomCells/XLFormCustomCell.swift new file mode 100644 index 0000000..89a5965 --- /dev/null +++ b/Examples/Swift/SwiftExample/Others/CustomCells/XLFormCustomCell.swift @@ -0,0 +1,57 @@ +// +// XLFormCustomCell.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +let XLFormRowDescriptorTypeCustom = "XLFormRowDescriptorTypeCustom" + +class XLFormCustomCell : XLFormBaseCell { + + override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + // override + self.textLabel!.text = self.rowDescriptor.value != nil ? self.rowDescriptor.value as? String : "Am a custom cell, select me!" + } + + + override func formDescriptorCellDidSelectedWithFormController(controller: XLFormViewController!) { + // custom code here + // i.e new behaviour when cell has been selected + self.rowDescriptor.value = self.rowDescriptor.value as? String == "I can do any custom behaviour..." ? "Am a custom cell, select me!" : "I can do any custom behaviour..." + self.update() + controller.tableView .selectRowAtIndexPath(nil, animated: true, scrollPosition: UITableViewScrollPosition.None) + } + +} diff --git a/Examples/Swift/SwiftExample/Others/OthersFormViewController.swift b/Examples/Swift/SwiftExample/Others/OthersFormViewController.swift new file mode 100755 index 0000000..e45686c --- /dev/null +++ b/Examples/Swift/SwiftExample/Others/OthersFormViewController.swift @@ -0,0 +1,183 @@ +// +// OthersFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import MapKit + +class OthersFormViewController : XLFormViewController { + + private enum Tags : String { + case SwitchBool = "switchBool" + case SwitchCheck = "switchCheck" + case StepCounter = "stepCounter" + case Slider = "slider" + case SegmentedControl = "segmentedControl" + case Custom = "custom" + case Info = "info" + case Button = "button" + case ButtonLeftAligned = "buttonLeftAligned" + case ButtonWithSegueId = "buttonWithSegueId" + case ButtonWithSegueClass = "buttonWithSegueClass" + case ButtonWithNibName = "buttonWithNibName" + case ButtonWithStoryboardId = "buttonWithStoryboardId" + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Other Cells") + + section = XLFormSectionDescriptor.formSectionWithTitle("Other Cells") + section.footerTitle = "OthersFormViewController.swift" + form.addFormSection(section) + + // Switch + section.addFormRow(XLFormRowDescriptor(tag: Tags.SwitchBool.rawValue, rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "Switch")) + + // Check + section.addFormRow(XLFormRowDescriptor(tag: Tags.SwitchCheck.rawValue, rowType: XLFormRowDescriptorTypeBooleanCheck, title: "Check")) + + // Step counter + section.addFormRow(XLFormRowDescriptor(tag: Tags.StepCounter.rawValue, rowType: XLFormRowDescriptorTypeStepCounter, title: "Step counter")) + + // Segmented Control + row = XLFormRowDescriptor(tag: Tags.SegmentedControl.rawValue, rowType: XLFormRowDescriptorTypeSelectorSegmentedControl, title: "Fruits") + row.selectorOptions = ["Apple", "Orange", "Pear"] + row.value = "Pear" + section.addFormRow(row) + + + // Slider + row = XLFormRowDescriptor(tag: Tags.Slider.rawValue, rowType: XLFormRowDescriptorTypeSlider, title: "Slider") + row.value = 30 + row.cellConfigAtConfigure["slider.maximumValue"] = 100 + row.cellConfigAtConfigure["slider.minimumValue"] = 10 + row.cellConfigAtConfigure["steps"] = 4 + section.addFormRow(row) + + + // Info cell + row = XLFormRowDescriptor(tag: Tags.Info.rawValue, rowType: XLFormRowDescriptorTypeInfo) + row.title = "Version" + row.value = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSectionWithTitle("Buttons") + section.footerTitle = "Blue buttons will show a message when Switch is ON" + form.addFormSection(section) + + // Button + row = XLFormRowDescriptor(tag: Tags.Button.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button") + row.cellConfig["textLabel.textColor"] = UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0) + row.action.formSelector = "didTouchButton:" + section.addFormRow(row) + + + // Left Button + row = XLFormRowDescriptor(tag: Tags.ButtonLeftAligned.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button with Block") + row.cellConfig["textLabel.textColor"] = UIColor(red: 0.0, green: 122.0/255.0, blue: 1.0, alpha: 1.0) + row.cellConfig["textLabel.textAlignment"] = NSTextAlignment.Left.rawValue + row.cellConfig["accessoryType"] = UITableViewCellAccessoryType.DisclosureIndicator.rawValue + row.action.formBlock = { (sender: XLFormRowDescriptor!) -> Void in + let switchRow = sender.sectionDescriptor.formDescriptor.formRowWithTag(Tags.SwitchBool.rawValue) + if switchRow.value != nil && switchRow.value!.boolValue == true { + let alertView = UIAlertView(title: "Switch is ON", message: "Button has checked the switch value...", delegate: self, cancelButtonTitle: "OK") + alertView.show() + } + self.deselectFormRow(sender) + } + section.addFormRow(row) + + + // Another Left Button with segue + row = XLFormRowDescriptor(tag: Tags.ButtonWithSegueClass.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button with Segue Class") + row.action.formSegueClass = NSClassFromString("UIStoryboardPushSegue") + row.action.viewControllerClass = MapViewController.self + row.value = CLLocation(latitude: -33.0, longitude: -56.0) + section.addFormRow(row) + + + // Button with SegueId + row = XLFormRowDescriptor(tag: Tags.ButtonWithSegueId.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button with Segue Idenfifier") + row.action.formSegueIdenfifier = "MapViewControllerSegue" + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + + // Another Button using StoryboardId + row = XLFormRowDescriptor(tag: Tags.ButtonWithStoryboardId.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button with StoryboardId") + row.action.viewControllerStoryboardId = "MapViewController" + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + // Button using NibName + row = XLFormRowDescriptor(tag: Tags.ButtonWithNibName.rawValue, rowType: XLFormRowDescriptorTypeButton, title: "Button with NibName") + row.action.viewControllerNibName = "MapViewController" + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + self.form = form + } + + + func didTouchButton(sender: XLFormRowDescriptor) { + if sender.sectionDescriptor.formDescriptor.formRowWithTag(Tags.SwitchBool.rawValue).value.boolValue == true{ + let alertView = UIAlertView(title: "Switch is ON", message: "Button has checked the switch value...", delegate: self, cancelButtonTitle: "OK") + alertView.show() + } + self.deselectFormRow(sender) + } + + override func viewDidLoad() { + super.viewDidLoad() + let barButton = UIBarButtonItem(title: "Disable", style: UIBarButtonItemStyle.Plain, target: self, action: "disableEnable:") + barButton.possibleTitles = Set(["Disable", "Enable"]) + self.navigationItem.rightBarButtonItem = barButton + } + + + func disableEnable(button : UIBarButtonItem) + { + self.form.disabled = !self.form.disabled + button.title = self.form.disabled ? "Enable" : "Disable" + self.tableView.endEditing(true) + self.tableView.reloadData() + } + +} diff --git a/Examples/Swift/SwiftExample/PredicateExamples/BasicPredicateViewController.swift b/Examples/Swift/SwiftExample/PredicateExamples/BasicPredicateViewController.swift new file mode 100644 index 0000000..1dcb436 --- /dev/null +++ b/Examples/Swift/SwiftExample/PredicateExamples/BasicPredicateViewController.swift @@ -0,0 +1,83 @@ +// +// BasicPredicateViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class BasicPredicateViewController : XLFormViewController { + + private enum Tags : String { + + case HideRow = "tag1" + case HideSection = "tag2" + case Text = "tag3" + + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Basic Predicates") + + section = XLFormSectionDescriptor() + section.title = "A Section" + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.HideRow.rawValue, rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "Show next row") + row.value = 0 + section.addFormRow(row) + + row = XLFormRowDescriptor(tag: Tags.HideSection.rawValue, rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "Show B Section") + row.hidden = "$\(Tags.HideRow.rawValue)==0" + row.value = 0 + section.addFormRow(row) + + section = XLFormSectionDescriptor() + section.title = "B Section" + section.footerTitle = "BasicPredicateViewController.swift" + section.hidden = "$\(Tags.HideSection.rawValue)==0" + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.Text.rawValue, rowType: XLFormRowDescriptorTypeText, title:nil) + row.cellConfigAtConfigure["textField.placeholder"] = "Gonna disappear soon!!" + section.addFormRow(row) + + self.form = form + + + } + +} diff --git a/Examples/Swift/SwiftExample/PredicateExamples/BlogExampleViewController.swift b/Examples/Swift/SwiftExample/PredicateExamples/BlogExampleViewController.swift new file mode 100644 index 0000000..3dba8c5 --- /dev/null +++ b/Examples/Swift/SwiftExample/PredicateExamples/BlogExampleViewController.swift @@ -0,0 +1,109 @@ +// +// BlogExampleViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "BlogExampleViewController.h" + +NSString *const kHobbies = @"hobbies"; +NSString *const kSport = @"sport"; +NSString *const kFilm = @"films1"; +NSString *const kFilm2 = @"films2"; +NSString *const kMusic = @"music"; + +@interface BlogExampleViewController () + +@end + +@implementation BlogExampleViewController +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + + +- (void)initializeForm +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + + form = [XLFormDescriptor formDescriptorWithTitle:@"Blog Example: Hobbies"]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Hobbies"]; + [form addFormSection:section]; + + XLFormRowDescriptor* hobbyRow = [XLFormRowDescriptor formRowDescriptorWithTag:kHobbies + rowType:XLFormRowDescriptorTypeMultipleSelector + title:@"Select Hobbies"]; + hobbyRow.selectorOptions = @[@"Sport", @"Music", @"Films"]; + hobbyRow.value = @[]; + [section addFormRow:hobbyRow]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Some more questions"]; + section.hidden = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"$%@.value.@count = 0", hobbyRow]]; + section.footerTitle = @"BlogExampleViewController.m"; + [form addFormSection:section]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kSport + rowType:XLFormRowDescriptorTypeTextView + title:@"Your favourite sportsman?"]; + row.hidden = [NSString stringWithFormat:@"NOT $%@.value contains 'Sport'", hobbyRow]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kFilm + rowType:XLFormRowDescriptorTypeTextView + title:@"Your favourite film?"]; + row.hidden = [NSString stringWithFormat:@"NOT $%@ contains 'Films'", hobbyRow]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kFilm2 + rowType:XLFormRowDescriptorTypeTextView + title:@"Your favourite actor?"]; + row.hidden = [NSString stringWithFormat:@"NOT $%@ contains 'Films'", hobbyRow]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kMusic + rowType:XLFormRowDescriptorTypeTextView + title:@"Your favourite singer?"]; + row.hidden = [NSString stringWithFormat:@"NOT $%@ contains 'Music'", hobbyRow]; + [section addFormRow:row]; + + self.form = form; +} + + +@end diff --git a/Examples/Swift/SwiftExample/PredicateExamples/PredicateFormViewController.swift b/Examples/Swift/SwiftExample/PredicateExamples/PredicateFormViewController.swift new file mode 100644 index 0000000..b342986 --- /dev/null +++ b/Examples/Swift/SwiftExample/PredicateExamples/PredicateFormViewController.swift @@ -0,0 +1,113 @@ +// +// PredicateFormViewController.m +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +NSString *const kPred = @"pred"; +NSString *const kPredDep = @"preddep"; +NSString *const kPredDep2 = @"preddep2"; + +#import "PredicateFormViewController.h" + +@implementation PredicateFormViewController + +- (instancetype)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initializeForm]; + } + return self; +} + +- (instancetype)init +{ + self = [super init]; + if (self) { + [self initializeForm]; + } + return self; +} + + +- (void)initializeForm +{ + XLFormDescriptor * form; + XLFormSectionDescriptor * section; + XLFormRowDescriptor * row; + XLFormRowDescriptor * pred, *pred3, *pred4; + + form = [XLFormDescriptor formDescriptorWithTitle:@"Predicates example"]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Independent rows"]; + + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPredDep rowType:XLFormRowDescriptorTypeAccount title:@"Text"]; + [row.cellConfigAtConfigure setObject:@"Type disable" forKey:@"textField.placeholder"]; + pred = row; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPredDep2 rowType:XLFormRowDescriptorTypeInteger title:@"Integer"]; + row.hidden = [NSString stringWithFormat:@"$switch==0"]; + [section addFormRow:row]; + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"switch" rowType:XLFormRowDescriptorTypeBooleanSwitch title:@"Boolean"]; + row.value = @1; + pred3 = row; + [section addFormRow:row]; + + [form addFormSection:section]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"Dependent section"]; + section.footerTitle = @"Type disable in the textfield, a number between 18 and 60 in the integer field or use the switch to disable the last row. By doing all three the last section will hide.\nThe integer field hides when the boolean switch is set to 0."; + [form addFormSection:section]; + + // Predicate Disabling + row = [XLFormRowDescriptor formRowDescriptorWithTag:kPred rowType:XLFormRowDescriptorTypeDateInline title:@"Disabled"]; + row.value = [NSDate new]; + [section addFormRow:row]; + + row.disabled = [NSString stringWithFormat:@"$%@ contains[c] 'disable' OR ($%@.value between {18, 60}) OR ($%@.value == 0)", pred, kPredDep2, pred3]; + //[NSPredicate predicateWithFormat:[NSString stringWithFormat:@"($%@.value contains[c] %%@) OR ($%@.value between {18, 60}) OR ($%@.value == 0)", pred, pred2, pred3], @"disable"] ]; + pred4 = row; + + section.hidden = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"($%@.value contains[c] 'disable') AND ($%@.value between {18, 60}) AND ($%@.value == 0)", pred, kPredDep2, pred3]]; + + section = [XLFormSectionDescriptor formSectionWithTitle:@"More predicates..."]; + section.footerTitle = @"This row hides when the row of the previous section is disabled and the textfield in the first section contains \"out\"\n\nPredicateFormViewController.m"; + [form addFormSection:section]; + + + + row = [XLFormRowDescriptor formRowDescriptorWithTag:@"thirds" rowType:XLFormRowDescriptorTypeAccount title:@"Account"]; + [section addFormRow:row]; + row.hidden = [NSString stringWithFormat:@"$%@.isDisabled == 1 AND $%@.value contains[c] 'Out'", pred4, pred]; + + + + + self.form = form; +} + + +@end diff --git a/Examples/Swift/SwiftExample/RealExamples/NativeEventFormViewController.swift b/Examples/Swift/SwiftExample/RealExamples/NativeEventFormViewController.swift new file mode 100644 index 0000000..7d72126 --- /dev/null +++ b/Examples/Swift/SwiftExample/RealExamples/NativeEventFormViewController.swift @@ -0,0 +1,245 @@ +// +// NativeEventNavigationViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class NativeEventFormViewController : XLFormViewController { + + + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + + form = XLFormDescriptor(title: "Add Event") + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // Title + row = XLFormRowDescriptor(tag: "title", rowType: XLFormRowDescriptorTypeText) + row.cellConfigAtConfigure["textField.placeholder"] = "Title" + row.required = true + section.addFormRow(row) + + // Location + row = XLFormRowDescriptor(tag: "location", rowType: XLFormRowDescriptorTypeText) + row.cellConfigAtConfigure["textField.placeholder"] = "Location" + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // All-day + row = XLFormRowDescriptor(tag: "all-day", rowType: XLFormRowDescriptorTypeBooleanSwitch, title: "All-day") + section.addFormRow(row) + + // Starts + row = XLFormRowDescriptor(tag: "starts", rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Starts") + row.value = NSDate(timeIntervalSinceNow: 60*60*24) + section.addFormRow(row) + + // Ends + row = XLFormRowDescriptor(tag: "ends", rowType: XLFormRowDescriptorTypeDateTimeInline, title: "Ends") + row.value = NSDate(timeIntervalSinceNow: 60*60*25) + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // Repeat + row = XLFormRowDescriptor(tag: "repeat", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Repeat") + row.value = XLFormOptionsObject(value: 0, displayText: "Never") + row.selectorTitle = "Repeat" + row.selectorOptions = [XLFormOptionsObject(value: 0, displayText: "Never"), + XLFormOptionsObject(value: 1, displayText: "Every Day"), + XLFormOptionsObject(value: 2, displayText: "Every Week"), + XLFormOptionsObject(value: 3, displayText: "Every 2 Weeks"), + XLFormOptionsObject(value: 4, displayText: "Every Month"), + XLFormOptionsObject(value: 5, displayText: "Every Year")] + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // Alert + row = XLFormRowDescriptor(tag: "alert", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Alert") + row.value = XLFormOptionsObject(value: 0, displayText: "None") + row.selectorTitle = "Event Alert" + row.selectorOptions = [ + XLFormOptionsObject(value: 0, displayText: "None"), + XLFormOptionsObject(value: 1, displayText: "At time of event"), + XLFormOptionsObject(value: 2, displayText: "5 minutes before"), + XLFormOptionsObject(value: 3, displayText: "15 minutes before"), + XLFormOptionsObject(value: 4, displayText: "30 minutes before"), + XLFormOptionsObject(value: 5, displayText: "1 hour before"), + XLFormOptionsObject(value: 6, displayText: "2 hours before"), + XLFormOptionsObject(value: 7, displayText: "1 day before"), + XLFormOptionsObject(value: 8, displayText: "2 days before")] + section.addFormRow(row) + + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // Show As + row = XLFormRowDescriptor(tag: "showAs", rowType:XLFormRowDescriptorTypeSelectorPush, title:"Show As") + row.value = XLFormOptionsObject(value: 0, displayText: "Busy") + row.selectorTitle = "Show As" + row.selectorOptions = [XLFormOptionsObject(value: 0, displayText:"Busy"), + XLFormOptionsObject(value: 1, displayText:"Free")] + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection() + form.addFormSection(section) + + // URL + row = XLFormRowDescriptor(tag: "url", rowType:XLFormRowDescriptorTypeURL) + row.cellConfigAtConfigure["textField.placeholder"] = "URL" + section.addFormRow(row) + + // Notes + row = XLFormRowDescriptor(tag: "notes", rowType:XLFormRowDescriptorTypeTextView) + row.cellConfigAtConfigure["textView.placeholder"] = "Notes" + section.addFormRow(row) + + self.form = form + } + + override func viewDidLoad() + { + super.viewDidLoad() + self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Cancel, target: self, action: "cancelPressed:") + self.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Save, target: self, action: "savePressed:") + } + +// MARK: XLFormDescriptorDelegate + + override func formRowDescriptorValueHasChanged(formRow: XLFormRowDescriptor!, oldValue: AnyObject!, newValue: AnyObject!) { + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + if formRow.tag == "alert" { + if !formRow.value.valueData().isEqual(0) && oldValue.valueData().isEqual(0) { + + let newRow = formRow.copy() as! XLFormRowDescriptor + newRow.tag = "secondAlert" + newRow.title = "Second Alert" + self.form.addFormRow(newRow, afterRow:formRow) + } + else if !oldValue.valueData().isEqual(0) && newValue.valueData().isEqual(0) { + self.form.removeFormRowWithTag("secondAlert") + } + } + else if formRow.tag == "all-day" { + let startDateDescriptor = self.form.formRowWithTag("starts") + let endDateDescriptor = self.form.formRowWithTag("ends") + let dateStartCell: XLFormDateCell = self.form.formRowWithTag("starts").cellForFormController(self) as! XLFormDateCell + let dateEndCell: XLFormDateCell = self.form.formRowWithTag("ends").cellForFormController(self) as! XLFormDateCell + if formRow.value.valueData() as? Bool == true { + startDateDescriptor.valueTransformer = DateValueTrasformer.self + endDateDescriptor.valueTransformer = DateValueTrasformer.self + dateStartCell.formDatePickerMode = XLFormDateDatePickerMode.Date + dateEndCell.formDatePickerMode = XLFormDateDatePickerMode.Date + } + else{ + startDateDescriptor.valueTransformer = DateTimeValueTrasformer.self + endDateDescriptor.valueTransformer = DateTimeValueTrasformer.self + dateStartCell.formDatePickerMode = XLFormDateDatePickerMode.DateTime + dateEndCell.formDatePickerMode = XLFormDateDatePickerMode.DateTime + } + self.updateFormRow(startDateDescriptor) + self.updateFormRow(endDateDescriptor) + } + else if formRow.tag == "starts" { + let startDateDescriptor = self.form.formRowWithTag("starts") + let endDateDescriptor = self.form.formRowWithTag("ends") + let dateStartCell: XLFormDateCell = self.form.formRowWithTag("starts").cellForFormController(self) as! XLFormDateCell + let dateEndCell: XLFormDateCell = self.form.formRowWithTag("ends").cellForFormController(self) as! XLFormDateCell + if startDateDescriptor.value.compare(endDateDescriptor.value as! NSDate) == NSComparisonResult.OrderedDescending { + // startDateDescriptor is later than endDateDescriptor + endDateDescriptor.value = NSDate(timeInterval: 60*60*24, sinceDate: startDateDescriptor.value as! NSDate) + endDateDescriptor.cellConfig.removeObjectForKey("detailTextLabel.attributedText") + self.updateFormRow(endDateDescriptor) + } + } + else if formRow.tag == "ends" { + let startDateDescriptor = self.form.formRowWithTag("starts") + let endDateDescriptor = self.form.formRowWithTag("ends") + let dateEndCell = endDateDescriptor.cellForFormController(self) as! XLFormDateCell + if startDateDescriptor.value.compare(endDateDescriptor.value as! NSDate) == NSComparisonResult.OrderedDescending { + // startDateDescriptor is later than endDateDescriptor + dateEndCell.update() + let newDetailText : String = dateEndCell.detailTextLabel!.text! + let strikeThroughAttribute = [NSStrikethroughStyleAttributeName : NSUnderlineStyle.StyleSingle.rawValue] + let strikeThroughText = NSAttributedString(string: newDetailText, attributes: strikeThroughAttribute) + endDateDescriptor.cellConfig["detailTextLabel.attributedText"] = strikeThroughText + self.updateFormRow(endDateDescriptor) + } + else{ + let endDateDescriptor = self.form.formRowWithTag("ends") + endDateDescriptor.cellConfig.removeObjectForKey("detailTextLabel.attributedText") + self.updateFormRow(endDateDescriptor) + } + } + } + + func cancelPressed(button: UIBarButtonItem) + { + self.dismissViewControllerAnimated(true, completion: nil) + } + + + func savePressed(button: UIBarButtonItem) + { + let validationErrors : Array = self.formValidationErrors() as! Array + if (validationErrors.count > 0){ + self.showFormValidationError(validationErrors.first) + return + } + self.tableView.endEditing(true) + } +} + + +class NativeEventNavigationViewController : UINavigationController { + + override func viewDidLoad(){ + super.viewDidLoad() + self.view.tintColor = UIColor.redColor() + } + +} diff --git a/Examples/Swift/SwiftExample/SelectorsFormViewController.swift b/Examples/Swift/SwiftExample/SelectorsFormViewController.swift new file mode 100644 index 0000000..6c6bbb1 --- /dev/null +++ b/Examples/Swift/SwiftExample/SelectorsFormViewController.swift @@ -0,0 +1,288 @@ +// +// SelectorsFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +import MapKit + +// Mark - NSValueTransformer + +class NSArrayValueTrasformer : NSValueTransformer { + + override class func transformedValueClass() -> AnyClass { + return NSString.self + } + + + override class func allowsReverseTransformation() -> Bool { + return false + } + + override func transformedValue(value: AnyObject?) -> AnyObject? { + if let arrayValue = value as? Array { + return String(format: "%d Item%@", arrayValue.count, arrayValue.count > 1 ? "s" : "") + } + else if let stringValue = value as? String { + return String(format: "%@ - ) - Transformed", stringValue) + } + return nil + } +} + +class ISOLanguageCodesValueTranformer : NSValueTransformer { + + override class func transformedValueClass() -> AnyClass { + return NSString.self + } + + + override class func allowsReverseTransformation() -> Bool { + return false + } + + override func transformedValue(value: AnyObject?) -> AnyObject? { + if let stringValue = value as? String { + return NSLocale.currentLocale().displayNameForKey(NSLocaleLanguageCode, value: stringValue) + } + return nil + } +} + +// Mark - SelectorsFormViewController + +class SelectorsFormViewController : XLFormViewController { + + private enum Tags : String { + case Push = "selectorPush" + case Popover = "selectorPopover" + case ActionSheet = "selectorActionSheet" + case AlertView = "selectorAlertView" + case PickerView = "selectorPickerView" + case Picker = "selectorPicker" + case PickerViewInline = "selectorPickerViewInline" + case MultipleSelector = "multipleSelector" + case MultipleSelectorPopover = "multipleSelectorPopover" + case DynamicSelectors = "dynamicSelectors" + case CustomSelectors = "customSelectors" + case SelectorWithSegueId = "selectorWithSegueId" + case SelectorWithSegueClass = "selectorWithSegueClass" + case SelectorWithNibName = "selectorWithNibName" + case SelectorWithStoryboardId = "selectorWithStoryboardId" + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + override func viewDidLoad() { + super.viewDidLoad() + let barButton = UIBarButtonItem(title: "Disable", style: UIBarButtonItemStyle.Plain, target: self, action: "disableEnable:") + barButton.possibleTitles = Set(["Disable", "Enable"]) + self.navigationItem.rightBarButtonItem = barButton + } + + func disableEnable(button : UIBarButtonItem) + { + self.form.disabled = !self.form.disabled + button.title = self.form.disabled ? "Enable" : "Disable" + self.tableView.endEditing(true) + self.tableView.reloadData() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Selectors") + section = XLFormSectionDescriptor.formSectionWithTitle("Selectors") + section.footerTitle = "SelectorsFormViewController.swift" + form.addFormSection(section) + + + // Selector Push + row = XLFormRowDescriptor(tag: Tags.Push.rawValue, rowType:XLFormRowDescriptorTypeSelectorPush, title:"Push") + row.selectorOptions = [XLFormOptionsObject(value: 0, displayText: "Option 1"), + XLFormOptionsObject(value: 1, displayText:"Option 2"), + XLFormOptionsObject(value: 2, displayText:"Option 3"), + XLFormOptionsObject(value: 3, displayText:"Option 4"), + XLFormOptionsObject(value: 4, displayText:"Option 5") + ] + row.value = XLFormOptionsObject(value: 1, displayText:"Option 2") + section.addFormRow(row) + + + // Selector Popover + if (UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad){ + row = XLFormRowDescriptor(tag: Tags.Popover.rawValue, rowType:XLFormRowDescriptorTypeSelectorPopover, title:"PopOver") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6"] + row.value = "Option 2" + section.addFormRow(row) + } + + // Selector Action Sheet + row = XLFormRowDescriptor(tag :Tags.ActionSheet.rawValue, rowType:XLFormRowDescriptorTypeSelectorActionSheet, title:"Sheet") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + row.value = "Option 3" + section.addFormRow(row) + + + + // Selector Alert View + row = XLFormRowDescriptor(tag: Tags.AlertView.rawValue, rowType:XLFormRowDescriptorTypeSelectorAlertView, title:"Alert View") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + row.value = "Option 3" + section.addFormRow(row) + + // Selector Picker View + row = XLFormRowDescriptor(tag: Tags.PickerView.rawValue, rowType:XLFormRowDescriptorTypeSelectorPickerView, title:"Picker View") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + row.value = "Option 4" + section.addFormRow(row) + + + // --------- Fixed Controls + section = XLFormSectionDescriptor.formSectionWithTitle("Fixed Controls") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.Picker.rawValue, rowType:XLFormRowDescriptorTypePicker) + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5"] + row.value = "Option 1" + section.addFormRow(row) + + // --------- Inline Selectors + section = XLFormSectionDescriptor.formSectionWithTitle("Inline Selectors") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.MultipleSelector.rawValue, rowType:XLFormRowDescriptorTypeSelectorPickerViewInline, title:"Inline Picker View") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6"] + row.value = "Option 6" + section.addFormRow(row) + + // --------- MultipleSelector + section = XLFormSectionDescriptor.formSectionWithTitle("Multiple Selectors") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.MultipleSelector.rawValue, rowType:XLFormRowDescriptorTypeMultipleSelector, title:"Multiple Selector") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6"] + row.value = ["Option 1", "Option 3", "Option 4", "Option 5", "Option 6"] + section.addFormRow(row) + + + // Multiple selector with value tranformer + row = XLFormRowDescriptor(tag: Tags.MultipleSelector.rawValue, rowType:XLFormRowDescriptorTypeMultipleSelector, title:"Multiple Selector") + row.selectorOptions = ["Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6"] + row.value = ["Option 1", "Option 3", "Option 4", "Option 5", "Option 6"] + row.valueTransformer = NSArrayValueTrasformer.self + section.addFormRow(row) + + + // Language multiple selector + row = XLFormRowDescriptor(tag: Tags.MultipleSelector.rawValue, rowType:XLFormRowDescriptorTypeMultipleSelector, title:"Multiple Selector") + row.selectorOptions = NSLocale.ISOLanguageCodes() + row.selectorTitle = "Languages" + row.valueTransformer = ISOLanguageCodesValueTranformer.self + row.value = NSLocale.preferredLanguages() + section.addFormRow(row) + + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad { + // Language multiple selector popover + row = XLFormRowDescriptor(tag: Tags.MultipleSelectorPopover.rawValue, rowType:XLFormRowDescriptorTypeMultipleSelectorPopover, title:"Multiple Selector PopOver") + row.selectorOptions = NSLocale.ISOLanguageCodes() + row.valueTransformer = ISOLanguageCodesValueTranformer.self + row.value = NSLocale.preferredLanguages() + section.addFormRow(row) + } + + + + // --------- Dynamic Selectors + section = XLFormSectionDescriptor.formSectionWithTitle("Dynamic Selectors") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.DynamicSelectors.rawValue, rowType:XLFormRowDescriptorTypeButton, title:"Dynamic Selectors") + row.action.viewControllerClass = DynamicSelectorsFormViewController.self + section.addFormRow(row) + + + + // --------- Custom Selectors + section = XLFormSectionDescriptor.formSectionWithTitle("Custom Selectors") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: Tags.CustomSelectors.rawValue, rowType:XLFormRowDescriptorTypeButton, title:"Custom Selectors") + row.action.viewControllerClass = CustomSelectorsFormViewController.self + section.addFormRow(row) + + + // --------- Selector definition types + section = XLFormSectionDescriptor.formSectionWithTitle("Selectors") + form.addFormSection(section) + + // selector with segue class + row = XLFormRowDescriptor(tag: Tags.SelectorWithSegueClass.rawValue, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Selector with Segue Class") + row.action.formSegueClass = NSClassFromString("UIStoryboardPushSegue") + row.action.viewControllerClass = MapViewController.self + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + // selector with SegueId + row = XLFormRowDescriptor(tag: Tags.SelectorWithSegueId.rawValue, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Selector with Segue Idenfifier") + row.action.formSegueIdenfifier = "MapViewControllerSegue"; + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + // selector using StoryboardId + row = XLFormRowDescriptor(tag: Tags.SelectorWithStoryboardId.rawValue, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Selector with StoryboardId") + row.action.viewControllerStoryboardId = "MapViewController"; + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + // selector with NibName + row = XLFormRowDescriptor(tag: Tags.SelectorWithNibName.rawValue, rowType: XLFormRowDescriptorTypeSelectorPush, title: "Selector with NibName") + row.action.viewControllerNibName = "MapViewController" + row.valueTransformer = CLLocationValueTrasformer.self + row.value = CLLocation(latitude: -33, longitude: -56) + section.addFormRow(row) + + self.form = form + } + + + override func storyboardForRow(formRow: XLFormRowDescriptor!) -> UIStoryboard! { + return UIStoryboard(name: "iPhoneStoryboard", bundle:nil) + } + +} diff --git a/Examples/Swift/SwiftExample/StoryboardExample/iPhoneStoryboard.storyboard b/Examples/Swift/SwiftExample/StoryboardExample/iPhoneStoryboard.storyboard new file mode 100644 index 0000000..fbb068b --- /dev/null +++ b/Examples/Swift/SwiftExample/StoryboardExample/iPhoneStoryboard.storyboard @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/Swift/SwiftExample/SwiftExample-Bridging-Header.h b/Examples/Swift/SwiftExample/SwiftExample-Bridging-Header.h index 4311542..98900aa 100644 --- a/Examples/Swift/SwiftExample/SwiftExample-Bridging-Header.h +++ b/Examples/Swift/SwiftExample/SwiftExample-Bridging-Header.h @@ -1,14 +1,17 @@ // -// SwiftExample-Bridging-Header.h.h +// SwiftExample-Bridging-Header.h // SwiftExample // // Created by Martin Barreto on 3/10/15. -// Copyright (c) 2015 Xmartlabs. All rights reserved. +// Copyright (c) 2014-2015 Xmartlabs. All rights reserved. // #ifndef SwiftExample_SwiftExample_Bridging_Header_h_h #define SwiftExample_SwiftExample_Bridging_Header_h_h + #import +#import +#import #endif diff --git a/Examples/Swift/SwiftExample/UICustomization/UICustomizationFormViewController.swift b/Examples/Swift/SwiftExample/UICustomization/UICustomizationFormViewController.swift new file mode 100644 index 0000000..82bd977 --- /dev/null +++ b/Examples/Swift/SwiftExample/UICustomization/UICustomizationFormViewController.swift @@ -0,0 +1,95 @@ +// +// UICustomizationFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +class UICustomizationFormViewController : XLFormViewController { + + private enum Tags : String { + case Name = "Name" + case Button = "Button" + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "UI Customization") + + section = XLFormSectionDescriptor() + form.addFormSection(section) + + // Name + row = XLFormRowDescriptor(tag: Tags.Name.rawValue, rowType: XLFormRowDescriptorTypeText, title:"Name") + // change the background color + row.cellConfigAtConfigure["backgroundColor"] = UIColor.greenColor() + // font + row.cellConfig["textLabel.font"] = UIFont.systemFontOfSize(30) + // background color + row.cellConfig["textField.backgroundColor"] = UIColor.grayColor() + // font + row.cellConfig["textField.font"] = UIFont.systemFontOfSize(25) + // alignment + row.cellConfig["textField.textAlignment"] = NSTextAlignment.Right.rawValue + section.addFormRow(row) + + + // Section + section = XLFormSectionDescriptor() + form.addFormSection(section) + + //Button + row = XLFormRowDescriptor(tag: Tags.Button.rawValue, rowType: XLFormRowDescriptorTypeButton, title:"Button") + row.cellConfigAtConfigure["backgroundColor"] = UIColor.purpleColor() + row.cellConfig["textLabel.color"] = UIColor.whiteColor() + row.cellConfig["textLabel.font"] = UIFont.systemFontOfSize(40) + section.addFormRow(row) + + self.form = form + } + + override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + // change cell height of a particular cell + if self.form.formRowAtIndex(indexPath)?.tag == "Name" { + return 60.0 + } + else if self.form.formRowAtIndex(indexPath)?.tag == "Button" { + return 100.0 + } + return super.tableView(tableView, heightForRowAtIndexPath: indexPath) + } +} + diff --git a/Examples/Swift/SwiftExample/Validations/ValidationExamplesFormViewController.swift b/Examples/Swift/SwiftExample/Validations/ValidationExamplesFormViewController.swift new file mode 100644 index 0000000..9070d73 --- /dev/null +++ b/Examples/Swift/SwiftExample/Validations/ValidationExamplesFormViewController.swift @@ -0,0 +1,159 @@ +// +// ValidationExamplesFormViewController.swift +// XLForm ( https://github.com/xmartlabs/XLForm ) +// +// Copyright (c) 2014-2015 Xmartlabs ( http://xmartlabs.com ) +// +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +class ValidationExamplesFormViewController : XLFormViewController { + + private enum Tags : String { + case ValidationName = "Name" + case ValidationEmail = "Email" + case ValidationPassword = "Password" + case ValidationInteger = "Integer" + } + + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + self.initializeForm() + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.initializeForm() + } + + func initializeForm() { + + let form : XLFormDescriptor + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + form = XLFormDescriptor(title: "Text Fields") + + section = XLFormSectionDescriptor() + section.title = "Validation Required" + form.addFormSection(section) + + + // Name + row = XLFormRowDescriptor(tag: Tags.ValidationName.rawValue, rowType: XLFormRowDescriptorTypeText, title:"Name") + row.cellConfigAtConfigure["textField.placeholder"] = "Required..." + row.cellConfigAtConfigure["textField.textAlignment"] = NSTextAlignment.Right.rawValue + row.required = true + row.value = "Martin" + section.addFormRow(row) + + section = XLFormSectionDescriptor() + section.title = "Validation Email" + form.addFormSection(section) + + // Email + row = XLFormRowDescriptor(tag: Tags.ValidationEmail.rawValue, rowType: XLFormRowDescriptorTypeText, title:"Email") + row.cellConfigAtConfigure["textField.textAlignment"] = NSTextAlignment.Right.rawValue + row.required = false + row.value = "not valid email" + row.addValidator(XLFormValidator.emailValidator()) + section.addFormRow(row) + + + section = XLFormSectionDescriptor() + section.title = "Validation Password" + section.footerTitle = "between 6 and 32 charachers, 1 alphanumeric and 1 numeric" + form.addFormSection(section) + + // Password + row = XLFormRowDescriptor(tag: Tags.ValidationPassword.rawValue, rowType: XLFormRowDescriptorTypePassword, title:"Password") + row.cellConfigAtConfigure["textField.placeholder"] = "Required..." + row.cellConfigAtConfigure["textField.textAlignment"] = NSTextAlignment.Right.rawValue + row.required = true + row.addValidator(XLFormRegexValidator(msg: "At least 6, max 32 characters", andRegexString: "^(?=.*\\d)(?=.*[A-Za-z]).{6,32}$")) + section.addFormRow(row) + + + section = XLFormSectionDescriptor() + section.title = "Validation Numbers" + section.footerTitle = "grather than 50 and less than 100" + form.addFormSection(section) + + // Integer + row = XLFormRowDescriptor(tag: Tags.ValidationInteger.rawValue, rowType:XLFormRowDescriptorTypeInteger, title:"Integer") + row.cellConfigAtConfigure["textField.placeholder"] = "Required..." + row.cellConfigAtConfigure["textField.textAlignment"] = NSTextAlignment.Right.rawValue + row.required = true + row.addValidator(XLFormRegexValidator(msg: "grather than 50 and less than 100", andRegexString: "^([5-9][0-9]|100)$")) + section.addFormRow(row) + + self.form = form + + + } + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem?.target = self + self.navigationItem.rightBarButtonItem?.action = "validateForm:" + } + + + +//MARK: Actions + + func validateForm(buttonItem: UIBarButtonItem) { + let array = self.formValidationErrors() + for errorItem in array { + let error = errorItem as! NSError + let validationStatus : XLFormValidationStatus = error.userInfo![XLValidationStatusErrorKey] as! XLFormValidationStatus + if validationStatus.rowDescriptor.tag == Tags.ValidationName.rawValue { + if let cell = self.tableView.cellForRowAtIndexPath(self.form.indexPathOfFormRow(validationStatus.rowDescriptor)) { + cell.backgroundColor = UIColor.orangeColor() + UIView.animateWithDuration(0.3, animations: { () -> Void in + cell.backgroundColor = UIColor.whiteColor() + }) + } + } + else if validationStatus.rowDescriptor.tag == Tags.ValidationEmail.rawValue || + validationStatus.rowDescriptor.tag == Tags.ValidationPassword.rawValue || + validationStatus.rowDescriptor.tag == Tags.ValidationInteger.rawValue { + if let cell = self.tableView.cellForRowAtIndexPath(self.form.indexPathOfFormRow(validationStatus.rowDescriptor)) { + self.animateCell(cell) + } + } + } + } + + +//MARK: - Helperph + + func animateCell(cell: UITableViewCell) { + let animation = CAKeyframeAnimation() + animation.keyPath = "position.x" + animation.values = [0, 20, -20, 10, 0] + animation.keyTimes = [0, (1 / 6.0), (3 / 6.0), (5 / 6.0), 1] + animation.duration = 0.3 + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) + animation.additive = true + cell.layer.addAnimation(animation, forKey: "shake") + } +}