Skip to content

Commit

Permalink
🎨 Customize Link-inline sign up view appearance (#913)
Browse files Browse the repository at this point in the history
* Customize link inline sign up appearance

* Styleize region placeholder

* Change text color for legal view

* Update from PR feedback

* set font lastt

* One more little hack

* Call super and fix border color

* update snapshots

* update more snapshots
  • Loading branch information
porter-stripe authored Mar 28, 2022
1 parent 6c6aa43 commit 69f7bbc
Show file tree
Hide file tree
Showing 28 changed files with 136 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,34 @@ class PaymentSheetSnapshotTests: FBSnapshotTestCase {
let imageView = UIImageView(image: screenshot)
verify(imageView)
}

func testLink() {
app.staticTexts["PaymentSheet (test playground)"].tap()
setupLink()
let screenshot = app.screenshot().image.removingStatusBar
let imageView = UIImageView(image: screenshot)
verify(imageView)
}

func testLink_darkMode() {
launchInDarkMode()
app.staticTexts["PaymentSheet (test playground)"].tap()
setupLink()
let screenshot = app.screenshot().image.removingStatusBar
let imageView = UIImageView(image: screenshot)
verify(imageView)
}

func testLinkWithAppearance() {
app.staticTexts["PaymentSheet (test playground)"].tap()
applySnapshotTestingAppearance()
setupLink()
let screenshot = app.screenshot().image.removingStatusBar
let imageView = UIImageView(image: screenshot)
verify(imageView)
}

// MARK: Common Helpers

private func testCard() {
app.staticTexts[
Expand Down Expand Up @@ -224,6 +252,28 @@ class PaymentSheetSnapshotTests: FBSnapshotTestCase {
XCTAssertTrue(app.buttons["Checkout (Complete)"].waitForExistence(timeout: 60.0))
}

private func setupLink() {
let apmSelector = app.segmentedControls["automatic_payment_methods_selector"]
XCTAssertTrue(apmSelector.waitForExistence(timeout: 60.0))
apmSelector.buttons["off"].tap()
app.segmentedControls["link_selector"].buttons["on"].tap()
reload()
app.buttons["Checkout (Complete)"].tap()

let saveSwitch = app.switches["Save my info for secure 1-click checkout"]
XCTAssertTrue(saveSwitch.waitForExistence(timeout: 60.0))
saveSwitch.tap()

let emailField = app.textFields["Email"]
XCTAssertTrue(emailField.waitForExistence(timeout: 60.0))
emailField.tap()
emailField.typeText("[email protected]")
emailField.typeText(XCUIKeyboardKey.return.rawValue)

app.scrollViews.firstMatch.scrollToElement(element: app.buttons["Pay $50.99"])
Thread.sleep(forTimeInterval: 1.0) // wait for scroll animation to finish
}

private func reload() {
app.buttons["Reload PaymentSheet"].tap()

Expand Down Expand Up @@ -278,3 +328,16 @@ private extension UIImage {
return nil
}
}

private extension XCUIElement {
func scrollToElement(element: XCUIElement) {
while !element.visible() {
swipeUp()
}
}

func visible() -> Bool {
guard self.exists && !self.frame.isEmpty else { return false }
return XCUIApplication().windows.element(boundBy: 0).frame.contains(self.frame)
}
}
10 changes: 10 additions & 0 deletions Stripe/LinkEmailElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ class LinkEmailElement: Element {
return emailAddressElement.validationState
}

public var indicatorTintColor: UIColor {
get {
return activityIndicator.color
}

set {
activityIndicator.color = newValue
}
}

public func startAnimating() {
activityIndicator.startAnimating()
}
Expand Down
3 changes: 2 additions & 1 deletion Stripe/LinkInlineSignupElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ final class LinkInlineSignupElement: Element {
self.init(viewModel: LinkInlineSignupViewModel(
merchantName: configuration.merchantDisplayName,
accountService: LinkAccountService(apiClient: configuration.apiClient),
linkAccount: linkAccount
linkAccount: linkAccount,
appearance: configuration.appearance
))
}

Expand Down
6 changes: 4 additions & 2 deletions Stripe/LinkInlineSignupView-CheckboxElement.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extension LinkInlineSignupView {
weak var delegate: ElementDelegate?

private let merchantName: String
private let appearance: PaymentSheet.Appearance

var view: UIView {
return checkboxButton
Expand All @@ -34,7 +35,7 @@ extension LinkInlineSignupView {
let checkbox = CheckboxButton(
text: "Save my info for secure 1-click checkout",
description: String(format: "Pay faster at %@ and thousands of merchants.", merchantName),
appearance: PaymentSheet.Appearance.default
appearance: appearance
)

checkbox.addTarget(self, action: #selector(didToggleCheckbox), for: .touchUpInside)
Expand All @@ -43,8 +44,9 @@ extension LinkInlineSignupView {
return checkbox
}()

init(merchantName: String) {
init(merchantName: String, appearance: PaymentSheet.Appearance) {
self.merchantName = merchantName
self.appearance = appearance
}

@objc func didToggleCheckbox() {
Expand Down
21 changes: 16 additions & 5 deletions Stripe/LinkInlineSignupView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,28 @@ final class LinkInlineSignupView: UIView {

let viewModel: LinkInlineSignupViewModel

private(set) lazy var checkboxElement = CheckboxElement(merchantName: viewModel.merchantName)
private(set) lazy var checkboxElement = CheckboxElement(merchantName: viewModel.merchantName,
appearance: viewModel.appearance)

private(set) lazy var emailElement = LinkEmailElement(defaultValue: viewModel.emailAddress)
private(set) lazy var emailElement : LinkEmailElement = {
let element = LinkEmailElement(defaultValue: viewModel.emailAddress)
element.indicatorTintColor = ElementsUITheme.current.colors.primary
return element
}()

private(set) lazy var phoneNumberElement = LinkPhoneNumberElement()

private(set) lazy var errorElement = StaticElement(view: ElementsUI.makeErrorLabel())

private(set) lazy var legalTermsElement = StaticElement(
view: LinkLegalTermsView(textAlignment: .left, delegate: self)
)
private(set) lazy var legalTermsElement: StaticElement = {
let legalView = LinkLegalTermsView(textAlignment: .left, delegate: self)
legalView.font = ElementsUITheme.current.fonts.caption
legalView.textColor = ElementsUITheme.current.colors.secondaryText

return StaticElement(
view: legalView
)
}()

private lazy var form = FormElement(elements: [
checkboxElement,
Expand Down
5 changes: 4 additions & 1 deletion Stripe/LinkInlineSignupViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ final class LinkInlineSignupViewModel {
private let accountLookupDebouncer = OperationDebouncer(debounceTime: .milliseconds(500))

let merchantName: String
let appearance: PaymentSheet.Appearance

var saveCheckboxChecked: Bool = false {
didSet {
Expand Down Expand Up @@ -125,12 +126,14 @@ final class LinkInlineSignupViewModel {
init(
merchantName: String,
accountService: LinkAccountServiceProtocol,
linkAccount: PaymentSheetLinkAccount? = nil
linkAccount: PaymentSheetLinkAccount? = nil,
appearance: PaymentSheet.Appearance = .default
) {
self.merchantName = merchantName
self.accountService = accountService
self.linkAccount = linkAccount
self.emailAddress = linkAccount?.email
self.appearance = appearance
}

}
Expand Down
17 changes: 11 additions & 6 deletions Stripe/LinkLegalTermsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,22 +44,32 @@ final class LinkLegalTermsView: UIView {
textView.textColor = newValue
}
}

var font: UIFont? {
get {
return textView.font
}
set {
textView.font = newValue
}
}

private lazy var textView: UITextView = {
let textView = UITextView()
textView.isScrollEnabled = false
textView.isEditable = false
textView.font = LinkUI.font(forTextStyle: .caption)
textView.backgroundColor = .clear
textView.attributedText = formattedLegalText()
textView.textColor = CompatibleColor.secondaryLabel
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.delegate = self
textView.clipsToBounds = false
textView.adjustsFontForContentSizeCategory = true
textView.linkTextAttributes = [
.underlineStyle: NSUnderlineStyle.single.rawValue
]
textView.font = LinkUI.font(forTextStyle: .caption)
return textView
}()

Expand All @@ -74,11 +84,6 @@ final class LinkLegalTermsView: UIView {
fatalError("init(coder:) has not been implemented")
}

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
textView.font = LinkUI.font(forTextStyle: .caption, compatibleWith: traitCollection)
}

private func formattedLegalText() -> NSAttributedString {
let string = STPLocalizedString(
"By joining Link, you agree to the <terms>Terms</terms> and <privacy>Privacy Policy</privacy>.",
Expand Down
10 changes: 10 additions & 0 deletions Stripe/PayWithLinkViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ final class PayWithLinkViewController: UINavigationController {
linkAccount: PaymentSheetLinkAccount?,
context: Context
) {
// TODO(porter): Hack, don't use payment sheet appearance in Link
ElementsUITheme.current = ElementsUITheme.default
self.linkAccount = linkAccount
self.context = context
super.init(nibName: nil, bundle: nil)
Expand All @@ -128,6 +130,12 @@ final class PayWithLinkViewController: UINavigationController {
view.tintColor = .linkBrand
updateUI()
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// TODO(porter): Hack, set appearance to payment sheet theme on dismiss
ElementsUITheme.current = context.configuration.appearance.asElementsTheme
}

override func pushViewController(_ viewController: UIViewController, animated: Bool) {
if let viewController = viewController as? BaseViewController {
Expand Down Expand Up @@ -267,6 +275,8 @@ extension PayWithLinkViewController: PayWithLinkCoordinating {
}

func cancel() {
// TODO(porter): Hack, set appearance to payment sheet theme on dismiss
ElementsUITheme.current = context.configuration.appearance.asElementsTheme
payWithLinkDelegate?.payWithLinkViewControllerDidCancel(self)
}

Expand Down
9 changes: 6 additions & 3 deletions StripeUICore/StripeUICore/Source/Elements/Form/FormView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ import UIKit
if viewModel.bordered {
let stack = StackViewWithSeparator(arrangedSubviews: viewModel.elements)
stack.drawBorder = true
stack.separatorColor = InputFormColors.outlineColor
stack.borderCornerRadius = 8
stack.customBackgroundColor = ElementsUITheme.current.colors.background
stack.separatorColor = ElementsUITheme.current.colors.divider
stack.borderColor = ElementsUITheme.current.colors.border
stack.borderCornerRadius = ElementsUITheme.current.shapes.cornerRadius
stack.spacing = ElementsUITheme.current.shapes.borderWidth
stack.layer.applyShadow(shape: ElementsUITheme.current.shapes)
stack.axis = .vertical
stack.spacing = 1
stack.distribution = .equalSpacing
addAndPinSubview(stack)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ import UIKit

private lazy var regionPrefixLabel: UILabel = {
let label = UILabel()
label.font = ElementsUI.textFieldFont
label.textColor = CompatibleColor.secondaryLabel
label.font = ElementsUITheme.current.fonts.subheadline
label.textColor = ElementsUITheme.current.colors.placeholderText
label.text = selectedMetadata?.prefix
return label
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ import UIKit
}
}

public var borderColor: UIColor = .clear {
public var borderColor: UIColor = CompatibleColor.systemGray3 {
didSet {
backgroundView.layer.borderColor = borderColor.cgColor
}
Expand Down Expand Up @@ -200,5 +200,12 @@ import UIKit
backgroundView.layer.shadowPath = hideShadow ? nil :
UIBezierPath(roundedRect: bounds, cornerRadius: borderCornerRadius).cgPath
}

public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
// CGColor's must be manually updated when the trait collection changes
backgroundView.layer.borderColor = borderColor.cgColor
separatorLayer.strokeColor = separatorColor.cgColor
}

}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified ...ntSheetSnapshotTests/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 69f7bbc

Please sign in to comment.