Skip to content

Commit

Permalink
Merge pull request #118 from afterpay/clearpay-svg
Browse files Browse the repository at this point in the history
Add Clearpay SVGs to the price breakdown component
  • Loading branch information
adamjcampbell authored Oct 15, 2020
2 parents 230e8dd + 9a48fa9 commit f3a37bf
Show file tree
Hide file tree
Showing 18 changed files with 414 additions and 78 deletions.
12 changes: 8 additions & 4 deletions Afterpay.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
objects = {

/* Begin PBXBuildFile section */
6602EF0F25358A8000A0468C /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6602EF0E25358A8000A0468C /* ColorScheme.swift */; };
6605666324E5199500DA588E /* Locales.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6605666224E5199500DA588E /* Locales.swift */; };
6615F99B24D14620005036F1 /* SVG.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6615F99A24D14620005036F1 /* SVG.swift */; };
661B233224DA8EE70010EBCD /* ColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 661B233124DA8EE70010EBCD /* ColorScheme.swift */; };
662A3AED24A999A500EFD826 /* CheckoutResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 662A3AEC24A999A500EFD826 /* CheckoutResult.swift */; };
6635B95F24CAA9F000EBB3A6 /* ConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6635B95E24CAA9F000EBB3A6 /* ConfigurationTests.swift */; };
6640C15224D8E1A700F7F4CC /* Macaw in Frameworks */ = {isa = PBXBuildFile; productRef = 6640C15124D8E1A700F7F4CC /* Macaw */; };
Expand All @@ -18,6 +18,7 @@
665FC57C2488766C00A5A93E /* Afterpay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 668F16072487653A0040345C /* Afterpay.framework */; };
66639B5424D2619200C68558 /* SVGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66639B5324D2619200C68558 /* SVGView.swift */; };
666D334C24A48F5C00FCD464 /* ObjcWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 666D334B24A48F5C00FCD464 /* ObjcWrapper.swift */; };
6672982A25357D80001D1C5A /* SVGConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6672982925357D80001D1C5A /* SVGConfiguration.swift */; };
667AD3542497121200BF94E5 /* CheckoutWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 667AD3532497121100BF94E5 /* CheckoutWebViewController.swift */; };
6689536C24C96CB5005090B4 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6689536B24C96CB5005090B4 /* Configuration.swift */; };
66D685B224BD3FB900C7287C /* SwiftUIWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D685B124BD3FB900C7287C /* SwiftUIWrapper.swift */; };
Expand All @@ -42,9 +43,9 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
6602EF0E25358A8000A0468C /* ColorScheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = "<group>"; };
6605666224E5199500DA588E /* Locales.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Locales.swift; sourceTree = "<group>"; };
6615F99A24D14620005036F1 /* SVG.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVG.swift; sourceTree = "<group>"; };
661B233124DA8EE70010EBCD /* ColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorScheme.swift; sourceTree = "<group>"; };
662A3AEC24A999A500EFD826 /* CheckoutResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckoutResult.swift; sourceTree = "<group>"; };
6632E0AE248A0171007F0BD9 /* Package.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Package.swift; sourceTree = "<group>"; };
6635B95E24CAA9F000EBB3A6 /* ConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationTests.swift; sourceTree = "<group>"; };
Expand All @@ -55,6 +56,7 @@
665FC5832488847900A5A93E /* Afterpay.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = Afterpay.xctestplan; sourceTree = "<group>"; };
66639B5324D2619200C68558 /* SVGView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVGView.swift; sourceTree = "<group>"; };
666D334B24A48F5C00FCD464 /* ObjcWrapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ObjcWrapper.swift; sourceTree = "<group>"; };
6672982925357D80001D1C5A /* SVGConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SVGConfiguration.swift; sourceTree = "<group>"; };
667AD3532497121100BF94E5 /* CheckoutWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckoutWebViewController.swift; sourceTree = "<group>"; };
6689536B24C96CB5005090B4 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
668F16072487653A0040345C /* Afterpay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Afterpay.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -104,7 +106,6 @@
isa = PBXGroup;
children = (
66EE378624D39FC50029BF42 /* BadgeView.swift */,
661B233124DA8EE70010EBCD /* ColorScheme.swift */,
66EE9BD624DCEC3D00A81C19 /* LinkTextView.swift */,
66483F3A24D7A164000BE6B5 /* PriceBreakdownView.swift */,
66639B5324D2619200C68558 /* SVGView.swift */,
Expand Down Expand Up @@ -234,8 +235,10 @@
66E255AC24E3BA2000C81F20 /* Resources */ = {
isa = PBXGroup;
children = (
6602EF0E25358A8000A0468C /* ColorScheme.swift */,
66E255AD24E3C14600C81F20 /* Strings.swift */,
6615F99A24D14620005036F1 /* SVG.swift */,
6672982925357D80001D1C5A /* SVGConfiguration.swift */,
);
path = Resources;
sourceTree = "<group>";
Expand Down Expand Up @@ -422,11 +425,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
661B233224DA8EE70010EBCD /* ColorScheme.swift in Sources */,
66639B5424D2619200C68558 /* SVGView.swift in Sources */,
66E255AE24E3C14600C81F20 /* Strings.swift in Sources */,
6615F99B24D14620005036F1 /* SVG.swift in Sources */,
66483F3B24D7A164000BE6B5 /* PriceBreakdownView.swift in Sources */,
6602EF0F25358A8000A0468C /* ColorScheme.swift in Sources */,
6672982A25357D80001D1C5A /* SVGConfiguration.swift in Sources */,
6689536C24C96CB5005090B4 /* Configuration.swift in Sources */,
66DAAC8B24E0CF0100127460 /* PriceBreakdown.swift in Sources */,
662A3AED24A999A500EFD826 /* CheckoutResult.swift in Sources */,
Expand Down
46 changes: 38 additions & 8 deletions AfterpayTests/ConfigurationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,38 @@ class ConfigurationTests: XCTestCase {
let usdCode = "USD"
let invalidCode = "XXX"

let usLocale = Locale(identifier: "en_US")

func testValidConfiguration() {
XCTAssertNoThrow(
try Configuration(minimumAmount: one, maximumAmount: oneThousand, currencyCode: usdCode)
try Configuration(
minimumAmount: one,
maximumAmount: oneThousand,
currencyCode: usdCode,
locale: usLocale
)
)
}

func testValidConfigurationNoMinimum() {
XCTAssertNoThrow(
try Configuration(minimumAmount: nil, maximumAmount: oneThousand, currencyCode: usdCode)
try Configuration(
minimumAmount: nil,
maximumAmount: oneThousand,
currencyCode: usdCode,
locale: usLocale
)
)
}

func testInvalidConfigurationInvalidCurrencyCode() {
XCTAssertThrowsError(
try Configuration(minimumAmount: one, maximumAmount: oneThousand, currencyCode: invalidCode)
try Configuration(
minimumAmount: one,
maximumAmount: oneThousand,
currencyCode: invalidCode,
locale: usLocale
)
) { error in
XCTAssertEqual(error as? ConfigurationError, .invalidCurrencyCode(invalidCode))
}
Expand All @@ -44,7 +61,8 @@ class ConfigurationTests: XCTestCase {
try Configuration(
minimumAmount: invalidAlphaAmount,
maximumAmount: oneThousand,
currencyCode: usdCode
currencyCode: usdCode,
locale: usLocale
)
) { error in
XCTAssertEqual(error as? ConfigurationError, .invalidMinimum(invalidAlphaAmount))
Expand All @@ -56,7 +74,8 @@ class ConfigurationTests: XCTestCase {
try Configuration(
minimumAmount: negativeAmount,
maximumAmount: oneThousand,
currencyCode: usdCode
currencyCode: usdCode,
locale: usLocale
)
) { error in
XCTAssertEqual(error as? ConfigurationError, .invalidMinimum(negativeAmount))
Expand All @@ -68,7 +87,8 @@ class ConfigurationTests: XCTestCase {
try Configuration(
minimumAmount: one,
maximumAmount: invalidAlphaAmount,
currencyCode: usdCode
currencyCode: usdCode,
locale: usLocale
)
) { error in
XCTAssertEqual(error as? ConfigurationError, .invalidMaximum(invalidAlphaAmount))
Expand All @@ -77,15 +97,25 @@ class ConfigurationTests: XCTestCase {

func testInvalidConfigurationInvalidMaximumWithNegatives() {
XCTAssertThrowsError(
try Configuration(minimumAmount: one, maximumAmount: negativeAmount, currencyCode: usdCode)
try Configuration(
minimumAmount: one,
maximumAmount: negativeAmount,
currencyCode: usdCode,
locale: usLocale
)
) { error in
XCTAssertEqual(error as? ConfigurationError, .invalidMaximum(negativeAmount))
}
}

func testInvalidConfigurationInvalidMinimumMaximumOrdering() {
XCTAssertThrowsError(
try Configuration(minimumAmount: oneThousand, maximumAmount: one, currencyCode: usdCode)
try Configuration(
minimumAmount: oneThousand,
maximumAmount: one,
currencyCode: usdCode,
locale: usLocale
)
) { error in
XCTAssertEqual(
error as? ConfigurationError,
Expand Down
14 changes: 12 additions & 2 deletions AfterpayTests/PriceBreakdownTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ class PriceBreakdownTests: XCTestCase {

private let setMinumumMaximumConfiguration = {
Afterpay.setConfiguration(
try? Configuration(minimumAmount: "50.00", maximumAmount: "200.00", currencyCode: "USD")
try? Configuration(
minimumAmount: "50.00",
maximumAmount: "200.00",
currencyCode: "USD",
locale: Locale(identifier: "en_US")
)
)
}

private let setMaximumConfiguration = {
Afterpay.setConfiguration(
try? Configuration(minimumAmount: nil, maximumAmount: "200.00", currencyCode: "USD")
try? Configuration(
minimumAmount: nil,
maximumAmount: "200.00",
currencyCode: "USD",
locale: Locale(identifier: "en_US")
)
)
}

Expand Down
151 changes: 149 additions & 2 deletions Example/Example/Components/ComponentsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,25 @@ final class ComponentsViewController:
{
// swiftlint:enable colon opening_brace

private var scrollView: UIScrollView!
private var pickerView: UIPickerView!
private var minimumAmountTextField: UITextField!
private var maximumAmountTextField: UITextField!
private var localeTextField: UITextField!
private var currencyTextField: UITextField!
private let localePickerDelegate = PickerDelegate( // swiftlint:disable:this weak_delegate
options: ["en_AU", "en_CA", "en_GB", "en_NZ", "en_US"],
getOption: { configurationStub.locale.identifier },
setOption: { configurationStub.locale = Locale(identifier: $0) })
private let currencyPickerDelegate = PickerDelegate( // swiftlint:disable:this weak_delegate
options: ["AUD", "CAD", "GBP", "NZD", "USD"],
getOption: { configurationStub.currencyCode },
setOption: { configurationStub.currencyCode = $0 })

override func loadView() {
let view = UIView()

let scrollView = UIScrollView()
scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = .appBackground
view.addSubview(scrollView)
Expand Down Expand Up @@ -131,16 +142,97 @@ final class ComponentsViewController:
maximumAmountTextField.inputAccessoryView = toolbar
configurationStack.addArrangedSubview(maximumAmountTextField)

let constraints = scrollViewConstraints + contentViewConstraints + stackConstraints + configurationStackConstraints
let localePicker = UIPickerView()

let localeTitle: UILabel = .bodyLabel
localeTitle.text = "Locale:"
configurationStack.addArrangedSubview(localeTitle)

localeTextField = .roundedTextField
localeTextField.inputAccessoryView = toolbar
configurationStack.addArrangedSubview(localeTextField)

localePickerDelegate.configure(updating: localeTextField, with: localePicker)

let currencyPicker = UIPickerView()

let currencyTitle: UILabel = .bodyLabel
currencyTitle.text = "Locale:"
configurationStack.addArrangedSubview(currencyTitle)

currencyTextField = .roundedTextField
currencyTextField.inputAccessoryView = toolbar
configurationStack.addArrangedSubview(currencyTextField)

currencyPickerDelegate.configure(updating: currencyTextField, with: currencyPicker)

let constraints = scrollViewConstraints
+ contentViewConstraints
+ stackConstraints
+ configurationStackConstraints

NSLayoutConstraint.activate(constraints)

self.view = view
}

override func viewDidLoad() {
super.viewDidLoad()

let notificationCenter = NotificationCenter.default
let selector = #selector(adjustForKeyboard)

notificationCenter.addObserver(
self,
selector: selector,
name: UIResponder.keyboardWillHideNotification,
object: nil
)

notificationCenter.addObserver(
self,
selector: selector,
name: UIResponder.keyboardWillChangeFrameNotification,
object: nil
)
}

@objc private func endEditing() {
view.endEditing(true)
}

@objc private func adjustForKeyboard(notification: Notification) {
guard
notification.name != UIResponder.keyboardWillHideNotification,
let keyboardFrameInfo = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey],
let keyboardHeight = (keyboardFrameInfo as? NSValue)?.cgRectValue.height
else {
scrollView.contentInset = .zero
scrollView.scrollIndicatorInsets = .zero
return
}

let insets = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight, right: 0)
scrollView.contentInset = insets
scrollView.scrollIndicatorInsets = insets

let textFields: [UITextField] = [
minimumAmountTextField,
maximumAmountTextField,
localeTextField,
currencyTextField,
]

let activeTextFieldOrigin = textFields
.first { $0.isFirstResponder }
.map { $0.frame.origin }

if let origin = activeTextFieldOrigin, !view.frame.contains(origin) {
let offset = CGPoint(x: 0, y: origin.y - keyboardHeight)
scrollView.setContentOffset(offset, animated: true)
}
}

// MARK: - UITextFieldDelegate

func textFieldDidBeginEditing(_ textField: UITextField) {
Expand Down Expand Up @@ -196,6 +288,61 @@ final class ComponentsViewController:

}

private final class PickerDelegate: NSObject, UIPickerViewDataSource, UIPickerViewDelegate {

private let options: [String]
private let getOption: () -> String
private let setOption: (String) -> Void

private weak var textField: UITextField?

init(
options: [String],
getOption: @escaping () -> String,
setOption: @escaping (String) -> Void
) {
self.options = options
self.getOption = getOption
self.setOption = setOption
}

func configure(updating textField: UITextField, with pickerView: UIPickerView) {
textField.text = getOption()
textField.inputView = pickerView

self.textField = textField

pickerView.delegate = self
pickerView.dataSource = self

if let row = options.firstIndex(of: getOption()) {
pickerView.selectRow(row, inComponent: 0, animated: false)
}
}

// MARK: UIPickerViewDataSource

func numberOfComponents(in pickerView: UIPickerView) -> Int { 1 }

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
options.count
}

// MARK: UIPickerViewDelegate

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
options[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
let identifier = options[row]

textField?.text = identifier
setOption(identifier)
}

}

private final class ContentStackViewController: UIViewController, PriceBreakdownViewDelegate {

let stackTitle: String
Expand Down
Loading

0 comments on commit f3a37bf

Please sign in to comment.