Skip to content

Commit

Permalink
Merge branch 'develop' into public-api-diff-action
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Guretzki committed Nov 15, 2024
2 parents 3ad588b + 4df1503 commit c090d5c
Show file tree
Hide file tree
Showing 270 changed files with 1,306 additions and 193 deletions.
4 changes: 4 additions & 0 deletions Adyen.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@
B6EE0F452BBECBEF00B9810D /* Adyen.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2C0E03322097917008616F6 /* Adyen.framework */; platformFilter = ios; };
C90D26A727565750001A488F /* FormViewController+ViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90D26A627565750001A488F /* FormViewController+ViewProtocol.swift */; };
C9126051275A3A2800C03DC4 /* BACSItemsFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9126050275A3A2800C03DC4 /* BACSItemsFactoryTests.swift */; };
C92665362C49346200D3D852 /* SubmittableComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = C92665352C49346200D3D852 /* SubmittableComponent.swift */; };
C927083827590B7500D15EA0 /* BACSInputFormViewProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90D26B1275900B9001A488F /* BACSInputFormViewProtocolMock.swift */; };
C927083927590B7900D15EA0 /* BACSInputPresenterProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90D26B32759048C001A488F /* BACSInputPresenterProtocolMock.swift */; };
C927083A27590B7D00D15EA0 /* BACSItemsFactoryProtocolMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90D26B5275905B8001A488F /* BACSItemsFactoryProtocolMock.swift */; };
Expand Down Expand Up @@ -1808,6 +1809,7 @@
C90D26B32759048C001A488F /* BACSInputPresenterProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSInputPresenterProtocolMock.swift; sourceTree = "<group>"; };
C90D26B5275905B8001A488F /* BACSItemsFactoryProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSItemsFactoryProtocolMock.swift; sourceTree = "<group>"; };
C9126050275A3A2800C03DC4 /* BACSItemsFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSItemsFactoryTests.swift; sourceTree = "<group>"; };
C92665352C49346200D3D852 /* SubmittableComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmittableComponent.swift; sourceTree = "<group>"; };
C927083D27590BDB00D15EA0 /* BACSInputFormViewControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSInputFormViewControllerTests.swift; sourceTree = "<group>"; };
C927083F27590FE800D15EA0 /* BACSInputPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSInputPresenterTests.swift; sourceTree = "<group>"; };
C92708412759106500D15EA0 /* BACSRouterProtocolMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BACSRouterProtocolMock.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4975,6 +4977,7 @@
E7D418B0286E4C5900E9A7F4 /* PaymentAwareComponent.swift */,
A0BC64E528F062E400CED2A1 /* AdyenSessionAware.swift */,
A09FB2EA2B8399B700270D51 /* TrackableComponent.swift */,
C92665352C49346200D3D852 /* SubmittableComponent.swift */,
A001297B2C0DF2E0009EF80C /* StoredPaymentMethodsDelegate.swift */,
A0644AB628A5120C00BBF4A9 /* StorePaymentMethodFieldAware.swift */,
);
Expand Down Expand Up @@ -7088,6 +7091,7 @@
E7085D7D262EEF6200D0153B /* AllRegions.swift in Sources */,
F919DF9124E682480027976E /* ClientKeyResponse.swift in Sources */,
F97C81AF25BAC8E600D7F85C /* AbstractPersonalInformationComponent.swift in Sources */,
C92665362C49346200D3D852 /* SubmittableComponent.swift in Sources */,
F97842D726C2758E00677458 /* InstantPaymentMethod.swift in Sources */,
F97CCD3C24360A4000BC560A /* BundleHelpers.swift in Sources */,
C9B6683727C8D7FB006950B9 /* AnalyticsData.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ extension AbstractPersonalInformationComponent: LoadingComponent {
}

internal func didSelectSubmitButton() {
guard formViewController.validate() else { return }
guard validate() else { return }

button.showsActivityIndicator = true
formViewController.view.isUserInteractionEnabled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ open class AbstractPersonalInformationComponent: PaymentComponent, PresentableCo

internal lazy var formViewController: FormViewController = {
let formViewController = FormViewController(
scrollEnabled: configuration.showsSubmitButton,
style: configuration.style,
localizationParameters: configuration.localizationParameters
)
Expand Down Expand Up @@ -75,9 +76,12 @@ open class AbstractPersonalInformationComponent: PaymentComponent, PresentableCo
fields.forEach { field in
self.add(field, into: formViewController)
}
formViewController.append(FormSpacerItem())
formViewController.append(button)
formViewController.append(FormSpacerItem(numberOfSpaces: 2))

if configuration.showsSubmitButton {
formViewController.append(FormSpacerItem())
formViewController.append(button)
}
formViewController.append(FormSpacerItem(numberOfSpaces: 4))
}

private func add(
Expand Down Expand Up @@ -283,3 +287,16 @@ extension AbstractPersonalInformationComponent: ViewControllerDelegate {
sendDidLoadEvent()
}
}

// MARK: - SubmitCustomizable

extension AbstractPersonalInformationComponent: SubmittableComponent {

public func submit() {
didSelectSubmitButton()
}

public func validate() -> Bool {
formViewController.validate()
}
}
2 changes: 1 addition & 1 deletion Adyen/Core/Components/AnyCashAppPayConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import Foundation

/// Describes any configuration for the Cash App Pay component.
public protocol AnyCashAppPayConfiguration {

/// The URL for Cash App to call in order to redirect back to your application.
var redirectURL: URL { get }

Expand Down
23 changes: 19 additions & 4 deletions Adyen/Core/Components/Base/BasicComponentConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,27 @@ public struct BasicComponentConfiguration: AnyBasicComponentConfiguration {

/// The UI style of the component.
public var style: FormComponentStyle


/// A Boolean value that determines whether the payment button is displayed. Defaults to `true`.
@_spi(AdyenInternal)
public private(set) var showsSubmitButton: Bool

public var localizationParameters: LocalizationParameters?

/// Initializes a new instance of `BasicComponentConfiguration`
///
/// - Parameters:
/// - style: The form style.
/// - showsSubmitButton: Boolean value that determines whether the payment button is displayed.
/// Defaults to `true`.
/// - localizationParameters: The localization parameters.
public init(
style: FormComponentStyle = FormComponentStyle(),
showsSubmitButton: Bool = true,
localizationParameters: LocalizationParameters? = nil
) {
self.style = style
self.showsSubmitButton = showsSubmitButton
self.localizationParameters = localizationParameters
}

Expand All @@ -44,23 +52,30 @@ public struct PersonalInformationConfiguration: AnyPersonalInformationConfigurat

/// The UI style of the component.
public var style: FormComponentStyle


/// A Boolean value that determines whether the payment button is displayed. Defaults to `true`.
internal let showsSubmitButton: Bool

public var shopperInformation: PrefilledShopperInformation?

public var localizationParameters: LocalizationParameters?

/// Initializes a new instance of `PersonalInformationConfiguration`
///
/// - Parameters:
/// - style: The form style.
/// - showsSubmitButton: Boolean value that determines whether the payment button is displayed.
/// Defaults to `true`.
/// - shopperInformation: The shopper information to be prefilled.
/// - localizationParameters: The localization parameters.
public init(
style: FormComponentStyle = FormComponentStyle(),
showsSubmitButton: Bool = true,
shopperInformation: PrefilledShopperInformation? = nil,
localizationParameters: LocalizationParameters? = nil
) {
self.style = style
self.showsSubmitButton = showsSubmitButton
self.shopperInformation = shopperInformation
self.localizationParameters = localizationParameters
}
Expand Down
1 change: 0 additions & 1 deletion Adyen/Core/Core Protocols/PaymentComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ extension PaymentComponent {
let logEvent = AnalyticsEventLog(component: paymentMethod.type.rawValue, type: .submit)
context.analyticsProvider?.add(log: logEvent)
}

}

extension AdyenContextAware where Self: PaymentAware {
Expand Down
35 changes: 35 additions & 0 deletions Adyen/Core/Core Protocols/SubmittableComponent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2024 Adyen N.V.
//
// This file is open source and available under the MIT license. See the LICENSE file for more info.
//

import Foundation

/// A protocol that provides control over the submission process in a payment component.
public protocol SubmittableComponent: PaymentComponent {
/// Submits the payment request to initiate the payment process.
///
/// This method starts the payment flow in the payment component. It triggers the validation of the form associated
/// with the payment component and initiates the loading state.
/// Ensure that the loading state is appropriately stopped once the payment process is complete.
///
/// If the `showsSubmitButton` of the payment component is enabled, calling this method will have no effect and will simply return.
///
/// - Important:
/// - Ensure that the payment component is properly configured before calling this method.
/// - Handle stopping the loading state after the payment process is completed.
func submit()

/// Validates the component's form and triggers the associated validation UI.
///
/// This method checks the validity of the form linked to the payment component. It ensures that all required fields are properly
/// filled out and conform to expected formats.
/// Additionally, it triggers the UI to visually indicate any validation errors to the user.
///
/// - Returns: A Boolean value indicating whether the form is valid (`true`) or not (`false`).
///
/// - Important:
/// - Make sure to call this method before initiating the payment process to ensure that the form is correctly filled out.
func validate() -> Bool
}
55 changes: 34 additions & 21 deletions Adyen/UI/Form/FormView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,27 @@
import UIKit

/// Displays a form for the user to enter details.
internal final class FormView: UIScrollView {
internal final class FormView: UIView {

// MARK: - UI elements

private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()

// MARK: - Properties

/// A Boolean value that determines whether the `FormView` is embedded in a `UIScrollView`
internal var isEmbeddedInScrollView: Bool = true

/// Initializes the form view.
internal init() {
super.init(frame: .zero)

preservesSuperviewLayoutMargins = true
addSubview(stackView)

configureConstraints()
setup()
}

@available(*, unavailable)
Expand All @@ -25,7 +36,7 @@ internal final class FormView: UIScrollView {
}

override internal var intrinsicContentSize: CGSize {
stackView.adyen.minimalSize
isEmbeddedInScrollView ? stackView.adyen.minimalSize : super.intrinsicContentSize
}

// MARK: - Item Views
Expand All @@ -37,21 +48,23 @@ internal final class FormView: UIScrollView {
stackView.addArrangedSubview(itemView)
}

// MARK: - Stack View

private lazy var stackView: UIStackView = {
let stackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .fill
stackView.preservesSuperviewLayoutMargins = true
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
// MARK: - Private

private func setup() {
addSubviews()
setupLayout()
}

// MARK: - Layout
private func addSubviews() {
addSubview(stackView)
}

private func configureConstraints() {
stackView.adyen.anchor(inside: self)
stackView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
private func setupLayout() {
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
stackView.bottomAnchor.constraint(lessThanOrEqualTo: bottomAnchor)
])
}
}
Loading

0 comments on commit c090d5c

Please sign in to comment.