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

[Native Checkout] Credit card cell #766

Merged
Merged
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
1 change: 1 addition & 0 deletions Kickstarter-iOS/Locales/Base.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Email_must_be_a_valid_email_address" = "Email must be a valid email address.";
"Email_notifications" = "Email notifications";
"Email_unverified" = "This email address is unverified.";
"Ending_in_last_four" = "Ending in %{last_four}";
"Ending_soon" = "Ending Soon";
"Estimated_delivery" = "Estimated delivery:";
"Estimated_delivery_of" = "Estimated delivery of";
Expand Down
1 change: 1 addition & 0 deletions Kickstarter-iOS/Locales/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Email_must_be_a_valid_email_address" = "E-Mail-Adresse muss gültig sein.";
"Email_notifications" = "Benachrichtigung per E-Mail";
"Email_unverified" = "Diese E-Mail-Adresse wurde noch nicht verifiziert.";
"Ending_in_last_four" = "Endet auf %{last_four}";
"Ending_soon" = "Endet bald";
"Estimated_delivery" = "Voraussichtliche Lieferung:";
"Estimated_delivery_of" = "Voraussichtliches Lieferdatum";
Expand Down
1 change: 1 addition & 0 deletions Kickstarter-iOS/Locales/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Email_must_be_a_valid_email_address" = "El correo electrónico debe tener una dirección de correo electrónico válida.";
"Email_notifications" = "Notificaciones por correo electrónico";
"Email_unverified" = "Esta dirección de correo electrónico no está verificada.";
"Ending_in_last_four" = "Número que termina en %{last_four}";
"Ending_soon" = "Finaliza pronto";
"Estimated_delivery" = "Entrega estimada:";
"Estimated_delivery_of" = "Entrega estimada de";
Expand Down
1 change: 1 addition & 0 deletions Kickstarter-iOS/Locales/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Email_must_be_a_valid_email_address" = "L'adresse e-mail doit être valide.";
"Email_notifications" = "Notifications par e-mail";
"Email_unverified" = "Adresse e-mail non vérifiée.";
"Ending_in_last_four" = "Finissant par %{last_four}";
"Ending_soon" = "Campagnes bientôt terminées";
"Estimated_delivery" = "Livraison prévue :";
"Estimated_delivery_of" = "Livraison prévue le";
Expand Down
1 change: 1 addition & 0 deletions Kickstarter-iOS/Locales/ja.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
"Email_must_be_a_valid_email_address" = "有効なメールアドレスを入力してください。";
"Email_notifications" = "メール通知設定";
"Email_unverified" = "このメールアドレスは認証されていません。";
"Ending_in_last_four" = "下の桁が%{last_four} の番号";
"Ending_soon" = "終了直前";
"Estimated_delivery" = "配達予定日:";
"Estimated_delivery_of" = "配送予定日";
Expand Down
2 changes: 1 addition & 1 deletion Kickstarter-iOS/Views/Cells/CreditCardCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ internal final class CreditCardCell: UITableViewCell, ValueCell {
super.bindViewModel()

self.cardNumberLabel.rac.accessibilityLabel = self.viewModel.outputs.cardNumberAccessibilityLabel
self.cardNumberLabel.rac.text = self.viewModel.outputs.cardNumberText
self.cardNumberLabel.rac.text = self.viewModel.outputs.cardNumberTextLongStyle
self.expirationDateLabel.rac.text = self.viewModel.outputs.expirationDateText

self.viewModel.outputs.cardImage
Expand Down
182 changes: 182 additions & 0 deletions Kickstarter-iOS/Views/Cells/PledgeCreditCardView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import KsApi
import Library
import Prelude
import UIKit

private enum Layout {
enum Card {
static let width: CGFloat = 240
}

enum ImageView {
static let width: CGFloat = 64
static let height: CGFloat = 40
}

enum Button {
static let width: CGFloat = 217
}
}

final class PledgeCreditCardView: UIView {
// MARK: - Properties

private let viewModel: CreditCardCellViewModelType = CreditCardCellViewModel()

private let adaptableStackView: UIStackView = { UIStackView(frame: .zero) }()
private let expirationDateLabel: UILabel = { UILabel(frame: .zero) }()
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we alphabetize these properties?

private let imageView: UIImageView = { UIImageView(frame: .zero) }()
private let labelsStackView: UIStackView = { UIStackView(frame: .zero) }()
private let lastFourLabel: UILabel = { UILabel(frame: .zero) }()
private let rootStackView: UIStackView = { UIStackView(frame: .zero) }()
private let selectButton: UIButton = { UIButton(type: .custom) }()

// MARK: - Lifecycle

override init(frame: CGRect) {
super.init(frame: frame)

self.configureSubviews()
self.setupConstraints()
self.bindViewModel()
}

required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

private func configureSubviews() {
_ = self
|> \.accessibilityElements .~ self.subviews

_ = ([self.lastFourLabel, self.expirationDateLabel], self.labelsStackView)
|> ksr_addArrangedSubviewsToStackView()

_ = ([self.imageView, self.labelsStackView], self.adaptableStackView)
|> ksr_addArrangedSubviewsToStackView()

_ = ([self.adaptableStackView, self.selectButton], self.rootStackView)
|> ksr_addArrangedSubviewsToStackView()

_ = (self.rootStackView, self)
|> ksr_addSubviewToParent()
|> ksr_constrainViewToMarginsInParent()
}

private func setupConstraints() {
NSLayoutConstraint.activate([
self.rootStackView.widthAnchor.constraint(equalToConstant: Layout.Card.width),
self.selectButton.heightAnchor.constraint(greaterThanOrEqualToConstant: Styles.minTouchSize.height),
self.imageView.widthAnchor.constraint(equalToConstant: Layout.ImageView.width)
])
}

// MARK: - Styles

override func bindStyles() {
super.bindStyles()

_ = self
|> viewStyle

_ = self.selectButton
|> selectButtonStyle

_ = self.selectButton.titleLabel
?|> selectButtonTitleLabelStyle

_ = self.imageView
|> imageViewStyle

_ = self.lastFourLabel
|> lastFourLabelStyle

_ = self.expirationDateLabel
|> expirationDateLabelStyle

_ = self.labelsStackView
|> labelsStackViewStyle

_ = self.adaptableStackView
|> checkoutAdaptableStackViewStyle(
self.traitCollection.preferredContentSizeCategory.isAccessibilityCategory
)
|> adaptableStackViewStyle

_ = self.rootStackView
|> rootStackViewStyle
}

override func bindViewModel() {
super.bindViewModel()

self.expirationDateLabel.rac.text = self.viewModel.outputs.expirationDateText
self.lastFourLabel.rac.text = self.viewModel.outputs.cardNumberTextShortStyle
self.viewModel.outputs.cardImage
.observeForUI()
.observeValues { [weak self] image in
_ = self?.imageView
?|> \.image .~ image
}
}

func configureWith(value: GraphUserCreditCard.CreditCard) {
self.viewModel.inputs.configureWith(creditCard: value)
}
}

// MARK: - Styles

private let adaptableStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.spacing .~ Styles.grid(2)
}

private let expirationDateLabelStyle: LabelStyle = { label in
label
|> checkoutTitleLabelStyle
|> \.font .~ UIFont.ksr_caption2().bolded
|> \.textColor .~ .ksr_text_dark_grey_500
}

private let imageViewStyle: ImageViewStyle = { imageView in
imageView
|> \.contentMode .~ .scaleAspectFit
}

private let lastFourLabelStyle: LabelStyle = { label in
label
|> checkoutTitleLabelStyle
|> \.font .~ UIFont.ksr_callout().bolded
|> \.textColor .~ .ksr_soft_black
}

private let labelsStackViewStyle: StackViewStyle = { stackView in
stackView
|> \.axis .~ .vertical
|> \.spacing .~ Styles.gridHalf(1)
}

private let rootStackViewStyle: StackViewStyle = { stackView in
stackView
|> checkoutStackViewStyle
|> \.spacing .~ Styles.grid(3)
}

private let selectButtonStyle: ButtonStyle = { button in
button
|> checkoutSmallBlackButtonStyle
|> UIButton.lens.title(for: .normal) %~ { _ in Strings.Select() }
}

private let selectButtonTitleLabelStyle: LabelStyle = { label in
label
|> \.font .~ UIFont.ksr_headline()
}

private let viewStyle: ViewStyle = { view in
view
|> \.backgroundColor .~ .white
|> roundedStyle(cornerRadius: Styles.grid(1))
|> \.layoutMargins .~ UIEdgeInsets(topBottom: Styles.grid(3), leftRight: Styles.grid(2))
}
Loading