Skip to content

Commit

Permalink
Propagate CardViewController closure to open card scanner to `FormCar…
Browse files Browse the repository at this point in the history
…dNumberItem`
  • Loading branch information
atmamont committed Mar 4, 2025
1 parent f366064 commit 985a4ca
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 31 deletions.
4 changes: 4 additions & 0 deletions Adyen.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,7 @@
A0F4559B295F0F58001742C7 /* MealVoucherPaymentMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F4559A295F0F58001742C7 /* MealVoucherPaymentMethod.swift */; };
A0F455A12968472B001742C7 /* PartialPaymentMethodDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0F455A02968472B001742C7 /* PartialPaymentMethodDetails.swift */; };
A0FA143F26D65A5300627127 /* InstallmentPickerElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0FA143E26D65A5300627127 /* InstallmentPickerElement.swift */; };
B62A075C2D71FB43006072E7 /* FormCardNumberItemView+ScanYourCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = B62A075B2D71FB43006072E7 /* FormCardNumberItemView+ScanYourCard.swift */; };
B62D48B42BBE8DBE001EF01A /* AnalyticsFlavorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16AB280702B200534419 /* AnalyticsFlavorTests.swift */; };
B62D48B52BBE8DBE001EF01A /* AnalyticsEventTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97C16A928059A5A00534419 /* AnalyticsEventTests.swift */; };
B62D48B72BBE8DBE001EF01A /* AnalyticsProviderMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C0005B280468E100CE2EEC /* AnalyticsProviderMock.swift */; };
Expand Down Expand Up @@ -1839,6 +1840,7 @@
A0F4559A295F0F58001742C7 /* MealVoucherPaymentMethod.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealVoucherPaymentMethod.swift; sourceTree = "<group>"; };
A0F455A02968472B001742C7 /* PartialPaymentMethodDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PartialPaymentMethodDetails.swift; sourceTree = "<group>"; };
A0FA143E26D65A5300627127 /* InstallmentPickerElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstallmentPickerElement.swift; sourceTree = "<group>"; };
B62A075B2D71FB43006072E7 /* FormCardNumberItemView+ScanYourCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FormCardNumberItemView+ScanYourCard.swift"; sourceTree = "<group>"; };
B62D48AC2BBE8D79001EF01A /* UnitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
B62D48C22BBE8ED6001EF01A /* XCTestCase+Wait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "XCTestCase+Wait.swift"; sourceTree = "<group>"; };
B62D48CA2BBE9059001EF01A /* UnitTests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UnitTests.xctestplan; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3975,6 +3977,7 @@
A04BD78126D510E1008E270F /* Installments */,
E2B317A42265D76600C1BB30 /* FormCardNumberItem.swift */,
E2B317A62265D7B700C1BB30 /* FormCardNumberItemView.swift */,
B62A075B2D71FB43006072E7 /* FormCardNumberItemView+ScanYourCard.swift */,
E76EC67F241125E0009C6E2F /* FormCardSecurityCodeItem.swift */,
E76EC681241125F5009C6E2F /* FormCardSecurityCodeItemView.swift */,
A01DCF0A26BD67BB00BC35B3 /* FormCardExpiryDateItem.swift */,
Expand Down Expand Up @@ -7513,6 +7516,7 @@
F92329DD25AD049E002C5BC4 /* FallbackCardBrandProvider.swift in Sources */,
E7798569268CE1B900CECA95 /* KCPDetails.swift in Sources */,
B6C9DA792D0C3F62005D65C7 /* DualBrandView.swift in Sources */,
B62A075C2D71FB43006072E7 /* FormCardNumberItemView+ScanYourCard.swift in Sources */,
F92CBA072811754400367820 /* GiftCardConfirmationPaymentMethod.swift in Sources */,
E9E3DACD221EEAB200697074 /* CardSecurityCodeValidator.swift in Sources */,
F96286B5256BDEA400043FE3 /* CardBundleExtension.swift in Sources */,
Expand Down
46 changes: 31 additions & 15 deletions AdyenCard/Components/Card/CardViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ internal class CardViewController: FormViewController {
localizationParameters: localizationParameters,
addressViewModelBuilder: DefaultAddressViewModelBuilder(),
presenter: self,
addressMode: configuration.billingAddress.mode
addressMode: configuration.billingAddress.mode,
scanCardHandler: { [weak self] in self?.openCardScanner() }
)
}()

Expand Down Expand Up @@ -100,6 +101,7 @@ internal class CardViewController: FormViewController {
override internal func viewDidLoad() {
setupView()
setupViewRelations()
setupCardScanning()
observeNumberItem()
super.viewDidLoad()
}
Expand Down Expand Up @@ -252,32 +254,32 @@ extension CardViewController {
items.socialSecurityNumberItem.isHidden.wrappedValue = shouldHideSocialSecurityItem(with: brand)
items.installmentsItem?.update(cardType: brand?.type)
}

// MARK: Private methods

private func setupView() {
append(items.numberContainerItem)

if configuration.showsSecurityCodeField {
let splitTextItem = FormSplitItem(items: items.expiryDateItem, items.securityCodeItem, style: formStyle.textField)
append(splitTextItem)
} else {
append(items.expiryDateItem)
}

if configuration.showsHolderNameField {
append(items.holderNameItem)
}

if configuration.koreanAuthenticationMode != .hide {
append(items.additionalAuthCodeItem)
append(items.additionalAuthPasswordItem)
}

if configuration.socialSecurityNumberMode != .hide {
append(items.socialSecurityNumberItem)
}

if let installmentsItem = items.installmentsItem {
append(installmentsItem)
}
Expand All @@ -290,7 +292,7 @@ extension CardViewController {
if let billingAddressItem {
append(billingAddressItem)
}

if configuration.showsSubmitButton {
append(FormSpacerItem())
append(items.button)
Expand All @@ -303,7 +305,7 @@ extension CardViewController {
switch configuration.billingAddress.mode {
case .lookup:
return items.billingAddressPickerItem

case .full:
return items.billingAddressPickerItem

Expand All @@ -314,18 +316,18 @@ extension CardViewController {
return nil
}
}

private func prefill() {
guard let shopperInformation else { return }

shopperInformation.billingAddress.map { billingAddress in
items.billingAddressPickerItem?.value = billingAddress
billingAddress.postalCode.map { items.postalCodeItem.value = $0 }
}
shopperInformation.card.map { items.holderNameItem.value = $0.holderName }
shopperInformation.socialSecurityNumber.map { items.socialSecurityNumberItem.value = $0 }
}

private func setupViewRelations() {
observe(items.numberContainerItem.numberItem.publisher) { [weak self] in self?.didChange(pan: $0) }
observe(items.numberContainerItem.numberItem.$binValue) { [weak self] in self?.didChange(bin: $0) }
Expand All @@ -334,7 +336,7 @@ extension CardViewController {
cardDelegate?.didSelectSubmitButton()
}
}

private func didChange(pan: String) {
items.securityCodeItem.selectedCard = supportedCardTypes.adyen.type(forCardNumber: pan)
cardDelegate?.didChange(pan: pan)
Expand Down Expand Up @@ -366,7 +368,6 @@ extension CardViewController {
return !brand.showsSocialSecurityNumber
}
}

}

internal protocol CardViewControllerDelegate: AnyObject {
Expand Down Expand Up @@ -398,6 +399,21 @@ extension CardViewController: CardViewControllerProtocol {
}
}

// MARK: - Card scanner

extension CardViewController {
private func setupCardScanning() {
if #available(iOS 13.0, *) {
// items.numberContainerItem.numberItem.view.inputAccessoryView = ...

}
}

private func openCardScanner() {
print("Open card scanner")
}
}

extension CardBrand {

internal var securityCodeItemDisplayMode: FormCardSecurityCodeItem.DisplayMode {
Expand Down
18 changes: 6 additions & 12 deletions AdyenCard/Components/Card/CardViewControllerItemsProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,17 @@ extension CardViewController {
internal final class ItemsProvider {

private let formStyle: FormComponentStyle

private let amount: Amount?

private var localizationParameters: LocalizationParameters?

private let configuration: CardComponent.Configuration

private let shopperInformation: PrefilledShopperInformation?

private let cardLogos: [FormCardLogosItem.CardTypeLogo]

private let scope: String

private let initialCountry: String

private let addressViewModelBuilder: AddressViewModelBuilder

private let presenter: WeakReferenceViewControllerPresenter

private let addressMode: CardComponent.AddressFormType
private let scanCardHandler: () -> Void

/// Closure that is called when an event is triggered via the field items.
internal var onDidTriggerInfoEvent: ((InfoEventData) -> Void)?
Expand All @@ -53,7 +44,8 @@ extension CardViewController {
localizationParameters: LocalizationParameters?,
addressViewModelBuilder: AddressViewModelBuilder,
presenter: ViewControllerPresenter,
addressMode: CardComponent.AddressFormType
addressMode: CardComponent.AddressFormType,
scanCardHandler: @escaping (() -> Void)
) {
self.formStyle = formStyle
self.amount = payment?.amount
Expand All @@ -66,6 +58,7 @@ extension CardViewController {
self.addressViewModelBuilder = addressViewModelBuilder
self.presenter = .init(presenter)
self.addressMode = addressMode
self.scanCardHandler = scanCardHandler
}

internal lazy var billingAddressPickerItem: FormAddressPickerItem? = {
Expand Down Expand Up @@ -111,7 +104,8 @@ extension CardViewController {
cardTypeLogos: cardLogos,
showsSupportedCardLogos: configuration.showsSupportedCardLogos,
style: formStyle.textField,
localizationParameters: localizationParameters
localizationParameters: localizationParameters,
scanCardHandler: scanCardHandler
)
item.identifier = ViewIdentifierBuilder.build(scopeInstance: scope, postfix: "numberContainerItem")

Expand Down
9 changes: 7 additions & 2 deletions AdyenCard/Form/FormCardNumberContainerItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ internal final class FormCardNumberContainerItem: FormItem, AdyenObserver {
internal let showsSupportedCardLogos: Bool

private let localizationParameters: LocalizationParameters?

private let scanCardHandler: () -> Void

internal lazy var subitems: [FormItem] = {
var subItems: [FormItem] = [numberItem]
Expand All @@ -35,7 +37,8 @@ internal final class FormCardNumberContainerItem: FormItem, AdyenObserver {
let item = FormCardNumberItem(
cardTypeLogos: cardTypeLogos,
style: style,
localizationParameters: localizationParameters
localizationParameters: localizationParameters,
scanCardHandler: scanCardHandler
)
item.identifier = ViewIdentifierBuilder.build(scopeInstance: self, postfix: "numberItem")
return item
Expand All @@ -51,12 +54,14 @@ internal final class FormCardNumberContainerItem: FormItem, AdyenObserver {
cardTypeLogos: [FormCardLogosItem.CardTypeLogo],
showsSupportedCardLogos: Bool = true,
style: FormTextItemStyle,
localizationParameters: LocalizationParameters?
localizationParameters: LocalizationParameters?,
scanCardHandler: @escaping (() -> Void)
) {
self.cardTypeLogos = cardTypeLogos
self.showsSupportedCardLogos = showsSupportedCardLogos
self.localizationParameters = localizationParameters
self.style = style
self.scanCardHandler = scanCardHandler

if showsSupportedCardLogos {
observe(numberItem.$isActive) { [weak self] _ in
Expand Down
7 changes: 5 additions & 2 deletions AdyenCard/Form/FormCardNumberItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ internal final class FormCardNumberItem: FormTextItem, AdyenObserver {

private let localizationParameters: LocalizationParameters?

internal let scanCardHandler: () -> Void

/// Returns the initial brand for single brand cases
/// or `selectedDualBrand` for dual brand cases
internal var currentBrand: CardBrand? {
Expand All @@ -57,7 +59,8 @@ internal final class FormCardNumberItem: FormTextItem, AdyenObserver {
internal init(
cardTypeLogos: [FormCardLogosItem.CardTypeLogo],
style: FormTextItemStyle = FormTextItemStyle(),
localizationParameters: LocalizationParameters? = nil
localizationParameters: LocalizationParameters? = nil,
scanCardHandler: @escaping (() -> Void)
) {
// these 4 US debit brands are not to be displayed
// but should be supported so it's done here for now
Expand All @@ -68,8 +71,8 @@ internal final class FormCardNumberItem: FormTextItem, AdyenObserver {
logo.type != .nyce
}
self.supportedCardTypes = cardTypeLogos.map(\.type)

self.localizationParameters = localizationParameters
self.scanCardHandler = scanCardHandler

super.init(style: style)

Expand Down
1 change: 1 addition & 0 deletions AdyenCard/Form/FormCardNumberItemView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,6 @@ internal final class FormCardNumberItemView: FormTextItemView<FormCardNumberItem
}()

@objc private func openCardScanner() {
item.scanCardHandler()
}
}

0 comments on commit 985a4ca

Please sign in to comment.