Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Country selector #7

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cartfile
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "xmartlabs/Eureka" ~> 4.0
github "xmartlabs/Eureka" "master"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use 4.1 now

2 changes: 1 addition & 1 deletion Cartfile.resolved
Original file line number Diff line number Diff line change
@@ -1 +1 @@
github "xmartlabs/Eureka" "4.0.1"
github "xmartlabs/Eureka" "a9552a715293c4fc70e26177533461b0e8e7b572"
32 changes: 27 additions & 5 deletions Example/Example/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15C50" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="adJ-sV-KLQ">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
Expand All @@ -14,13 +18,31 @@
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
<navigationItem key="navigationItem" id="1SO-x1-pZA"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="436" y="133"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="UKt-41-Uco">
<objects>
<navigationController id="adJ-sV-KLQ" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="kFj-ka-BXA">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="BYZ-38-t0r" kind="relationship" relationship="rootViewController" id="Nid-qn-PBg"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="g8s-cj-0AQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-503" y="133"/>
</scene>
</scenes>
</document>
37 changes: 27 additions & 10 deletions Example/Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,33 @@ class ViewController: FormViewController {
$0.countryPlaceholder = "Country"
$0.postalCodePlaceholder = "Zip code"
}
+++ Section()
<<< MyPostalAddressRow() {
$0.streetPlaceholder = "Street"
$0.cityPlaceholder = "City"
$0.postalCodePlaceholder = "Zip code"
}.cellSetup({ (cell, row) in
cell.streetTextField?.font = .systemFont(ofSize: 18)
cell.postalCodeTextField?.font = .systemFont(ofSize: 18)
cell.cityTextField?.font = .systemFont(ofSize: 18)
})

+++ Section()
<<< PostalAddressRow() {
$0.streetPlaceholder = "Street"
$0.statePlaceholder = "State"
$0.cityPlaceholder = "City"
$0.countryPlaceholder = "Country"
$0.postalCodePlaceholder = "Zip code"

$0.countrySelectorRow = PushRow<String>(){
$0.options = ["GB","US"]
$0.displayValueFor = { guard let isoCode = $0 else{ return nil }
return Locale.current.localizedString(forRegionCode: isoCode)
}
}
}

+++ Section()
<<< MyPostalAddressRow() {
$0.streetPlaceholder = "Street"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you align this line to its context? Maybe if you set Xcode to replace tabs with spaces

$0.cityPlaceholder = "City"
$0.postalCodePlaceholder = "Zip code"
}.cellSetup({ (cell, row) in
cell.streetTextField?.font = .systemFont(ofSize: 18)
cell.postalCodeTextField?.font = .systemFont(ofSize: 18)
cell.cityTextField?.font = .systemFont(ofSize: 18)
})
}
}

143 changes: 118 additions & 25 deletions Sources/PostalAddressCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ public protocol PostalAddressCellConformance {
var postalCodeTextField: UITextField? { get }
var cityTextField: UITextField? { get }
var countryTextField: UITextField? { get }
var countrySelectorTableView: UITableView?{ get }
}

/// Base class that implements the cell logic for the PostalAddressRow
open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAddressCellConformance, UITextFieldDelegate {
open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAddressCellConformance, UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource {

@IBOutlet open var streetTextField: UITextField?
@IBOutlet open var firstSeparatorView: UIView?
Expand All @@ -32,10 +33,14 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
@IBOutlet open var cityTextField: UITextField?
@IBOutlet open var secondSeparatorView: UIView?
@IBOutlet open var countryTextField: UITextField?

@IBOutlet open var countrySelectorTableView: UITableView?

@IBOutlet weak var postalPercentageConstraint: NSLayoutConstraint?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove trailing whitespace

open var textFieldOrdering: [UITextField?] = []
var textFieldOrderingVisible: [UITextField?]{
return textFieldOrdering.filter{ $0?.isHidden == false }
}

public required init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
Expand All @@ -61,6 +66,8 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
cityTextField?.removeTarget(self, action: nil, for: .allEvents)
countryTextField?.delegate = nil
countryTextField?.removeTarget(self, action: nil, for: .allEvents)
countrySelectorTableView?.delegate = nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here for indentation.

countrySelectorTableView?.dataSource = nil
imageView?.removeObserver(self, forKeyPath: "image")
}

Expand All @@ -80,6 +87,47 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
textField?.delegate = self
textField?.font = .preferredFont(forTextStyle: UIFontTextStyle.body)
}

if (row as? PostalAddressRowConformance)?.countrySelectorRow == nil{
countrySelectorTableView?.isHidden = true
countryTextField?.isHidden = false
} else {
countrySelectorTableView?.isHidden = false
countryTextField?.isHidden = true
}

countrySelectorTableView?.isScrollEnabled = false
countrySelectorTableView?.sectionHeaderHeight = 0.0
countrySelectorTableView?.sectionFooterHeight = 0.0
countrySelectorTableView?.delegate = self
countrySelectorTableView?.dataSource = self

if let rowConformance = row as? PostalAddressRowConformance, let selectorRow = rowConformance.countrySelectorRow{
selectorRow
.onChange{ [weak self] in
guard let this = self else{ return }

var rowValue = this.row.value ?? T()
rowValue.country = $0.value
this.row.value = rowValue

$0.title = $0.displayValueFor?($0.value) ?? $0.noValueDisplayText ?? (this.row as? PostalAddressRowConformance)?.countryPlaceholder

this.row.updateCell()

}.cellSetup{ [weak self] cell, row in
cell.selectionStyle = .none
cell.detailTextLabel?.isHidden = true
cell.textLabel?.textColor = self?.row.value?.country == nil ? UIColor(red: 196.0/255.0, green: 196.0/255.0, blue: 196.0/255.0, alpha: 1.0) : (self?.row.isDisabled == true ? .gray : .black)

}.cellUpdate{ [weak self] cell, row in
cell.selectionStyle = .none
cell.textLabel?.textColor = self?.row.value?.country == nil ? UIColor(red: 196.0/255.0, green: 196.0/255.0, blue: 196.0/255.0, alpha: 1.0) : (self?.row.isDisabled == true ? .gray : .black)
}

selectorRow.baseCell.setup()
}


for separator in [firstSeparatorView, secondSeparatorView] {
separator?.backgroundColor = .gray
Expand Down Expand Up @@ -113,11 +161,15 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
countryTextField?.keyboardType = .asciiCapable

if let rowConformance = row as? PostalAddressRowConformance {
setPlaceholderToTextField(textField: streetTextField, placeholder: rowConformance.streetPlaceholder)
setPlaceholderToTextField(textField: streetTextField, placeholder: rowConformance.streetPlaceholder)
setPlaceholderToTextField(textField: stateTextField, placeholder: rowConformance.statePlaceholder)
setPlaceholderToTextField(textField: postalCodeTextField, placeholder: rowConformance.postalCodePlaceholder)
setPlaceholderToTextField(textField: cityTextField, placeholder: rowConformance.cityPlaceholder)
setPlaceholderToTextField(textField: countryTextField, placeholder: rowConformance.countryPlaceholder)

rowConformance.countrySelectorRow?.title = rowConformance.countrySelectorRow?.title ?? rowConformance.countryPlaceholder
rowConformance.countrySelectorRow?.selectorTitle = rowConformance.countrySelectorRow?.selectorTitle ?? rowConformance.countryPlaceholder
rowConformance.countrySelectorRow?.value = row.value?.country
}
}

Expand All @@ -137,12 +189,13 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
stateTextField?.canBecomeFirstResponder == true ||
postalCodeTextField?.canBecomeFirstResponder == true ||
cityTextField?.canBecomeFirstResponder == true ||
countryTextField?.canBecomeFirstResponder == true
countryTextField?.canBecomeFirstResponder == true ||
(row as? PostalAddressRowConformance)?.countrySelectorRow?.cell?.cellCanBecomeFirstResponder() == true
)
}

open override func cellBecomeFirstResponder(withDirection direction: Direction) -> Bool {
return direction == .down ? textFieldOrdering.first??.becomeFirstResponder() ?? false : textFieldOrdering.last??.becomeFirstResponder() ?? false
return direction == .down ? textFieldOrderingVisible.first??.becomeFirstResponder() ?? false : textFieldOrderingVisible.last??.becomeFirstResponder() ?? false
}

open override func cellResignFirstResponder() -> Bool {
Expand All @@ -152,11 +205,12 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
&& stateTextField?.resignFirstResponder() ?? true
&& cityTextField?.resignFirstResponder() ?? true
&& countryTextField?.resignFirstResponder() ?? true
&& (row as? PostalAddressRowConformance)?.countrySelectorRow?.cell?.cellResignFirstResponder() ?? true
}

override open var inputAccessoryView: UIView? {
if let v = formViewController()?.inputAccessoryView(for: row) as? NavigationAccessoryView {
guard let first = textFieldOrdering.first, let last = textFieldOrdering.last, first != last else { return v }
guard let first = textFieldOrderingVisible.first, let last = textFieldOrderingVisible.last, first != last else { return v }

if first?.isFirstResponder == true {
v.nextButton.isEnabled = true
Expand Down Expand Up @@ -185,9 +239,9 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
guard let inputAccesoryView = inputAccessoryView as? NavigationAccessoryView else { return }

var index = 0
for field in textFieldOrdering {
for field in textFieldOrderingVisible {
if field?.isFirstResponder == true {
let _ = sender == inputAccesoryView.previousButton ? textFieldOrdering[index-1]?.becomeFirstResponder() : textFieldOrdering[index+1]?.becomeFirstResponder()
let _ = sender == inputAccesoryView.previousButton ? textFieldOrderingVisible[index-1]?.becomeFirstResponder() : textFieldOrderingVisible[index+1]?.becomeFirstResponder()
break
}
index += 1
Expand All @@ -204,11 +258,7 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
}

@objc open func textFieldDidChange(_ textField : UITextField){
if row.baseValue == nil{
row.baseValue = PostalAddress()
}

guard let textValue = textField.text else {
guard let textValue = textField.text else {
switch(textField){
case let field where field == streetTextField:
row.value?.street = nil
Expand Down Expand Up @@ -263,18 +313,19 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
let value: AutoreleasingUnsafeMutablePointer<AnyObject?> = AutoreleasingUnsafeMutablePointer<AnyObject?>.init(UnsafeMutablePointer<T>.allocate(capacity: 1))
let errorDesc: AutoreleasingUnsafeMutablePointer<NSString?>? = nil
if formatter.getObjectValue(value, for: textValue, errorDescription: errorDesc) {
var rowValue = row.value ?? T()

switch(textField){
case let field where field == streetTextField:
row.value?.street = value.pointee as? String
rowValue.street = value.pointee as? String
case let field where field == stateTextField:
row.value?.state = value.pointee as? String
rowValue.state = value.pointee as? String
case let field where field == postalCodeTextField:
row.value?.postalCode = value.pointee as? String
rowValue.postalCode = value.pointee as? String
case let field where field == cityTextField:
row.value?.city = value.pointee as? String
rowValue.city = value.pointee as? String
case let field where field == countryTextField:
row.value?.country = value.pointee as? String
rowValue.country = value.pointee as? String
default:
break
}
Expand All @@ -287,6 +338,8 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
}
textField.selectedTextRange = textField.textRange(from: selStartPos, to: selStartPos)
}

row.value = rowValue
return
}
}
Expand All @@ -309,21 +362,23 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
}
return
}


var rowValue = row.value ?? T()
switch(textField){
case let field where field == streetTextField:
row.value?.street = textValue
rowValue.street = textValue
case let field where field == stateTextField:
row.value?.state = textValue
rowValue.state = textValue
case let field where field == postalCodeTextField:
row.value?.postalCode = textValue
rowValue.postalCode = textValue
case let field where field == cityTextField:
row.value?.city = textValue
rowValue.city = textValue
case let field where field == countryTextField:
row.value?.country = textValue
rowValue.country = textValue
default:
break
}
row.value = rowValue
}

//MARK: TextFieldDelegate
Expand Down Expand Up @@ -358,6 +413,44 @@ open class _PostalAddressCell<T: PostalAddressType>: Cell<T>, CellType, PostalAd
open func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
return formViewController()?.textInputShouldEndEditing(textField, cell: self) ?? true
}

//MARK: UITableViewDataSource

public func numberOfSections(in tableView: UITableView) -> Int {
guard let rowConformance = row as? PostalAddressRowConformance else{ return 0 }
return rowConformance.countrySelectorRow == nil ? 0 : 1
}

public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let rowConformance = row as? PostalAddressRowConformance else{ return 0 }
return rowConformance.countrySelectorRow == nil ? 0 : 1
}

//MARK: UITableViewDelegate

public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let row = (row as? PostalAddressRowConformance)?.countrySelectorRow else{ fatalError() }
return row.baseCell
}

public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let row = (row as? PostalAddressRowConformance)?.countrySelectorRow else{ return }

// row.baseCell.cellBecomeFirstResponder() may be cause InlineRow collapsed then section count will be changed. Use orignal indexPath will out of section's bounds.
if !row.baseCell.cellCanBecomeFirstResponder() || !row.baseCell.cellBecomeFirstResponder() {
tableView.endEditing(true)
}
row.didSelect()
}

public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let row = (row as? PostalAddressRowConformance)?.countrySelectorRow else{ return tableView.rowHeight }
return row.baseCell.height?() ?? tableView.rowHeight
}

public func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return false
}
}


Expand Down
Loading