├── .github
├── CHANGELOG.md
├── CODEOWNERS.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── PULL_REQUEST_TEMPLATE.md
├── docs
│ ├── Classes.html
│ ├── Classes
│ │ ├── CardValidator.html
│ │ ├── CheckoutAPIService.html
│ │ ├── CountrySelectionViewController.html
│ │ ├── DefaultAddBillingDetailsButtonStyle.html
│ │ ├── DefaultEditBillingDetailsButtonStyle.html
│ │ ├── PhoneValidator.html
│ │ ├── SecureDisplayView.html
│ │ ├── ThreeDSWKNavigationHelper.html
│ │ └── ThreedsWebViewController.html
│ ├── Enums.html
│ ├── Enums
│ │ ├── AccessibilityIdentifiers.html
│ │ ├── AccessibilityIdentifiers
│ │ │ ├── BillingForm.html
│ │ │ └── PaymentForm.html
│ │ ├── BillingFormCell.html
│ │ ├── CardScheme.html
│ │ ├── Constants.html
│ │ ├── Constants
│ │ │ └── Phone.html
│ │ ├── Environment.html
│ │ ├── FramesFactory.html
│ │ ├── FramesUIStyle.html
│ │ ├── NetworkError.html
│ │ ├── PaymentFormFactory.html
│ │ ├── PaymentSource.html
│ │ ├── ThreeDSError.html
│ │ ├── TokenisationError.html
│ │ ├── TokenisationError
│ │ │ ├── ServerError.html
│ │ │ └── TokenRequest.html
│ │ ├── ValidationError.html
│ │ ├── ValidationError
│ │ │ ├── Address.html
│ │ │ ├── CVV.html
│ │ │ ├── Card.html
│ │ │ ├── CardNumber.html
│ │ │ ├── EagerCardNumber.html
│ │ │ ├── ExpiryDate.html
│ │ │ └── Phone.html
│ │ └── ValidationResult.html
│ ├── Extensions.html
│ ├── Extensions
│ │ └── String.html
│ ├── Protocols.html
│ ├── Protocols
│ │ ├── BillingFormHeaderCellStyle.html
│ │ ├── BillingFormStyle.html
│ │ ├── BillingSummaryViewStyle.html
│ │ ├── CVVValidating.html
│ │ ├── CardNumberValidating.html
│ │ ├── CardValidating.html
│ │ ├── CellButtonStyle.html
│ │ ├── CellStyle.html
│ │ ├── CellTextFieldStyle.html
│ │ ├── CheckoutAPIProtocol.html
│ │ ├── CheckoutError.html
│ │ ├── CountrySelectionViewControllerDelegate.html
│ │ ├── ElementBorderStyle.html
│ │ ├── ElementButtonStyle.html
│ │ ├── ElementErrorViewStyle.html
│ │ ├── ElementStyle.html
│ │ ├── ElementTextFieldStyle.html
│ │ ├── ExpiryDateValidating.html
│ │ ├── PaymentFormStyle.html
│ │ ├── PaymentHeaderCellStyle.html
│ │ ├── PhoneValidating.html
│ │ ├── ThreeDSWKNavigationHelperDelegate.html
│ │ ├── ThreeDSWKNavigationHelping.html
│ │ └── ThreedsWebViewControllerDelegate.html
│ ├── Structs.html
│ ├── Structs
│ │ ├── Address.html
│ │ ├── ApplePay.html
│ │ ├── BillingForm.html
│ │ ├── Card.html
│ │ ├── Card
│ │ │ └── Scheme.html
│ │ ├── Country.html
│ │ ├── DefaultAddBillingDetailsViewStyle.html
│ │ ├── DefaultBillingFormAddressLine1CellStyle.html
│ │ ├── DefaultBillingFormAddressLine2CellStyle.html
│ │ ├── DefaultBillingFormCityCellStyle.html
│ │ ├── DefaultBillingFormCountryCellStyle.html
│ │ ├── DefaultBillingFormFullNameCellStyle.html
│ │ ├── DefaultBillingFormHeaderCellStyle.html
│ │ ├── DefaultBillingFormPhoneNumberCellStyle.html
│ │ ├── DefaultBillingFormPostcodeCellStyle.html
│ │ ├── DefaultBillingFormStateCellStyle.html
│ │ ├── DefaultBillingFormStyle.html
│ │ ├── DefaultBillingSummaryViewStyle.html
│ │ ├── DefaultBorderStyle.html
│ │ ├── DefaultCancelButtonFormStyle.html
│ │ ├── DefaultCardNumberFormStyle.html
│ │ ├── DefaultCardholderFormStyle.html
│ │ ├── DefaultCountryFormButtonStyle.html
│ │ ├── DefaultDoneFormButtonStyle.html
│ │ ├── DefaultErrorInputLabelStyle.html
│ │ ├── DefaultExpiryDateFormStyle.html
│ │ ├── DefaultHeaderLabelFormStyle.html
│ │ ├── DefaultHintInputLabelStyle.html
│ │ ├── DefaultPayButtonFormStyle.html
│ │ ├── DefaultPaymentFormStyle.html
│ │ ├── DefaultPaymentHeaderCellStyle.html
│ │ ├── DefaultSecurityCodeFormStyle.html
│ │ ├── DefaultTextField.html
│ │ ├── DefaultTitleLabelStyle.html
│ │ ├── ExpiryDate.html
│ │ ├── PaymentFormConfiguration.html
│ │ ├── PaymentStyle.html
│ │ ├── Phone.html
│ │ ├── Theme.html
│ │ ├── Theme
│ │ │ ├── CountryListButton.html
│ │ │ ├── NavigationButtonStyle.html
│ │ │ ├── ThemeAddBillingSectionButton.html
│ │ │ ├── ThemeBillingButton.html
│ │ │ ├── ThemeBillingCountryInput.html
│ │ │ ├── ThemeBillingForm.html
│ │ │ ├── ThemeBillingHeader.html
│ │ │ ├── ThemeBillingInput.html
│ │ │ ├── ThemeBillingModifyButton.html
│ │ │ ├── ThemeBillingSummary.html
│ │ │ ├── ThemeBorderStyle.html
│ │ │ ├── ThemeError.html
│ │ │ ├── ThemeMandatory.html
│ │ │ ├── ThemePageHeaderTitle.html
│ │ │ ├── ThemePayButton.html
│ │ │ ├── ThemePaymentForm.html
│ │ │ ├── ThemePaymentHeader.html
│ │ │ ├── ThemePaymentHeaderSubtitle.html
│ │ │ ├── ThemePaymentInput.html
│ │ │ ├── ThemeSubtitle.html
│ │ │ ├── ThemeSummaryElement.html
│ │ │ ├── ThemeTextField.html
│ │ │ └── ThemeTitle.html
│ │ ├── TokenDetails.html
│ │ └── TokenDetails
│ │ │ ├── Phone.html
│ │ │ └── TokenType.html
│ ├── Typealiases.html
│ ├── badge.svg
│ ├── css
│ │ ├── highlight.css
│ │ └── jazzy.css
│ ├── docsets
│ │ ├── Frames.docset
│ │ │ └── Contents
│ │ │ │ ├── Info.plist
│ │ │ │ └── Resources
│ │ │ │ ├── Documents
│ │ │ │ ├── Classes.html
│ │ │ │ ├── Classes
│ │ │ │ │ ├── CardValidator.html
│ │ │ │ │ ├── CheckoutAPIService.html
│ │ │ │ │ ├── CountrySelectionViewController.html
│ │ │ │ │ ├── DefaultAddBillingDetailsButtonStyle.html
│ │ │ │ │ ├── DefaultEditBillingDetailsButtonStyle.html
│ │ │ │ │ ├── PhoneValidator.html
│ │ │ │ │ ├── SecureDisplayView.html
│ │ │ │ │ ├── ThreeDSWKNavigationHelper.html
│ │ │ │ │ └── ThreedsWebViewController.html
│ │ │ │ ├── Enums.html
│ │ │ │ ├── Enums
│ │ │ │ │ ├── AccessibilityIdentifiers.html
│ │ │ │ │ ├── AccessibilityIdentifiers
│ │ │ │ │ │ ├── BillingForm.html
│ │ │ │ │ │ └── PaymentForm.html
│ │ │ │ │ ├── BillingFormCell.html
│ │ │ │ │ ├── CardScheme.html
│ │ │ │ │ ├── Constants.html
│ │ │ │ │ ├── Constants
│ │ │ │ │ │ └── Phone.html
│ │ │ │ │ ├── Environment.html
│ │ │ │ │ ├── FramesFactory.html
│ │ │ │ │ ├── FramesUIStyle.html
│ │ │ │ │ ├── NetworkError.html
│ │ │ │ │ ├── PaymentFormFactory.html
│ │ │ │ │ ├── PaymentSource.html
│ │ │ │ │ ├── ThreeDSError.html
│ │ │ │ │ ├── TokenisationError.html
│ │ │ │ │ ├── TokenisationError
│ │ │ │ │ │ ├── ServerError.html
│ │ │ │ │ │ └── TokenRequest.html
│ │ │ │ │ ├── ValidationError.html
│ │ │ │ │ ├── ValidationError
│ │ │ │ │ │ ├── Address.html
│ │ │ │ │ │ ├── CVV.html
│ │ │ │ │ │ ├── Card.html
│ │ │ │ │ │ ├── CardNumber.html
│ │ │ │ │ │ ├── EagerCardNumber.html
│ │ │ │ │ │ ├── ExpiryDate.html
│ │ │ │ │ │ └── Phone.html
│ │ │ │ │ └── ValidationResult.html
│ │ │ │ ├── Extensions.html
│ │ │ │ ├── Extensions
│ │ │ │ │ └── String.html
│ │ │ │ ├── Protocols.html
│ │ │ │ ├── Protocols
│ │ │ │ │ ├── BillingFormHeaderCellStyle.html
│ │ │ │ │ ├── BillingFormStyle.html
│ │ │ │ │ ├── BillingSummaryViewStyle.html
│ │ │ │ │ ├── CVVValidating.html
│ │ │ │ │ ├── CardNumberValidating.html
│ │ │ │ │ ├── CardValidating.html
│ │ │ │ │ ├── CellButtonStyle.html
│ │ │ │ │ ├── CellStyle.html
│ │ │ │ │ ├── CellTextFieldStyle.html
│ │ │ │ │ ├── CheckoutAPIProtocol.html
│ │ │ │ │ ├── CheckoutError.html
│ │ │ │ │ ├── CountrySelectionViewControllerDelegate.html
│ │ │ │ │ ├── ElementBorderStyle.html
│ │ │ │ │ ├── ElementButtonStyle.html
│ │ │ │ │ ├── ElementErrorViewStyle.html
│ │ │ │ │ ├── ElementStyle.html
│ │ │ │ │ ├── ElementTextFieldStyle.html
│ │ │ │ │ ├── ExpiryDateValidating.html
│ │ │ │ │ ├── PaymentFormStyle.html
│ │ │ │ │ ├── PaymentHeaderCellStyle.html
│ │ │ │ │ ├── PhoneValidating.html
│ │ │ │ │ ├── ThreeDSWKNavigationHelperDelegate.html
│ │ │ │ │ ├── ThreeDSWKNavigationHelping.html
│ │ │ │ │ └── ThreedsWebViewControllerDelegate.html
│ │ │ │ ├── Structs.html
│ │ │ │ ├── Structs
│ │ │ │ │ ├── Address.html
│ │ │ │ │ ├── ApplePay.html
│ │ │ │ │ ├── BillingForm.html
│ │ │ │ │ ├── Card.html
│ │ │ │ │ ├── Card
│ │ │ │ │ │ └── Scheme.html
│ │ │ │ │ ├── Country.html
│ │ │ │ │ ├── DefaultAddBillingDetailsViewStyle.html
│ │ │ │ │ ├── DefaultBillingFormAddressLine1CellStyle.html
│ │ │ │ │ ├── DefaultBillingFormAddressLine2CellStyle.html
│ │ │ │ │ ├── DefaultBillingFormCityCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormCountryCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormFullNameCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormHeaderCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormPhoneNumberCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormPostcodeCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormStateCellStyle.html
│ │ │ │ │ ├── DefaultBillingFormStyle.html
│ │ │ │ │ ├── DefaultBillingSummaryViewStyle.html
│ │ │ │ │ ├── DefaultBorderStyle.html
│ │ │ │ │ ├── DefaultCancelButtonFormStyle.html
│ │ │ │ │ ├── DefaultCardNumberFormStyle.html
│ │ │ │ │ ├── DefaultCardholderFormStyle.html
│ │ │ │ │ ├── DefaultCountryFormButtonStyle.html
│ │ │ │ │ ├── DefaultDoneFormButtonStyle.html
│ │ │ │ │ ├── DefaultErrorInputLabelStyle.html
│ │ │ │ │ ├── DefaultExpiryDateFormStyle.html
│ │ │ │ │ ├── DefaultHeaderLabelFormStyle.html
│ │ │ │ │ ├── DefaultHintInputLabelStyle.html
│ │ │ │ │ ├── DefaultPayButtonFormStyle.html
│ │ │ │ │ ├── DefaultPaymentFormStyle.html
│ │ │ │ │ ├── DefaultPaymentHeaderCellStyle.html
│ │ │ │ │ ├── DefaultSecurityCodeFormStyle.html
│ │ │ │ │ ├── DefaultTextField.html
│ │ │ │ │ ├── DefaultTitleLabelStyle.html
│ │ │ │ │ ├── ExpiryDate.html
│ │ │ │ │ ├── PaymentFormConfiguration.html
│ │ │ │ │ ├── PaymentStyle.html
│ │ │ │ │ ├── Phone.html
│ │ │ │ │ ├── Theme.html
│ │ │ │ │ ├── Theme
│ │ │ │ │ │ ├── CountryListButton.html
│ │ │ │ │ │ ├── NavigationButtonStyle.html
│ │ │ │ │ │ ├── ThemeAddBillingSectionButton.html
│ │ │ │ │ │ ├── ThemeBillingButton.html
│ │ │ │ │ │ ├── ThemeBillingCountryInput.html
│ │ │ │ │ │ ├── ThemeBillingForm.html
│ │ │ │ │ │ ├── ThemeBillingHeader.html
│ │ │ │ │ │ ├── ThemeBillingInput.html
│ │ │ │ │ │ ├── ThemeBillingModifyButton.html
│ │ │ │ │ │ ├── ThemeBillingSummary.html
│ │ │ │ │ │ ├── ThemeBorderStyle.html
│ │ │ │ │ │ ├── ThemeError.html
│ │ │ │ │ │ ├── ThemeMandatory.html
│ │ │ │ │ │ ├── ThemePageHeaderTitle.html
│ │ │ │ │ │ ├── ThemePayButton.html
│ │ │ │ │ │ ├── ThemePaymentForm.html
│ │ │ │ │ │ ├── ThemePaymentHeader.html
│ │ │ │ │ │ ├── ThemePaymentHeaderSubtitle.html
│ │ │ │ │ │ ├── ThemePaymentInput.html
│ │ │ │ │ │ ├── ThemeSubtitle.html
│ │ │ │ │ │ ├── ThemeSummaryElement.html
│ │ │ │ │ │ ├── ThemeTextField.html
│ │ │ │ │ │ └── ThemeTitle.html
│ │ │ │ │ ├── TokenDetails.html
│ │ │ │ │ └── TokenDetails
│ │ │ │ │ │ ├── Phone.html
│ │ │ │ │ │ └── TokenType.html
│ │ │ │ ├── Typealiases.html
│ │ │ │ ├── css
│ │ │ │ │ ├── highlight.css
│ │ │ │ │ └── jazzy.css
│ │ │ │ ├── img
│ │ │ │ │ ├── carat.png
│ │ │ │ │ ├── dash.png
│ │ │ │ │ ├── gh.png
│ │ │ │ │ └── spinner.gif
│ │ │ │ ├── index.html
│ │ │ │ ├── js
│ │ │ │ │ ├── jazzy.js
│ │ │ │ │ ├── jazzy.search.js
│ │ │ │ │ ├── jquery.min.js
│ │ │ │ │ ├── lunr.min.js
│ │ │ │ │ └── typeahead.jquery.js
│ │ │ │ └── search.json
│ │ │ │ └── docSet.dsidx
│ │ └── Frames.tgz
│ ├── img
│ │ ├── carat.png
│ │ ├── dash.png
│ │ ├── gh.png
│ │ └── spinner.gif
│ ├── index.html
│ ├── js
│ │ ├── jazzy.js
│ │ ├── jazzy.search.js
│ │ ├── jquery.min.js
│ │ ├── lunr.min.js
│ │ └── typeahead.jquery.js
│ ├── search.json
│ └── undocumented.json
├── media
│ ├── checkout-logo.png
│ ├── demo-frames-ios.gif
│ └── demo-frames-ios.webp
├── partial-readmes
│ ├── GetStarted.md
│ ├── Integration.md
│ ├── MakeItYourOwn.md
│ ├── Migration.md
│ ├── OtherFeatures.md
│ └── SecurityCodeComponent.md
├── scripts
│ ├── buildDocs.sh
│ └── lintEditedFiles.sh
└── workflows
│ ├── check-pr.yml
│ ├── codeql-analysis.yml
│ ├── deploy-github-pages.yml
│ ├── generate-jazzy-docs.yml
│ ├── publish-Checkout.podspec.yml
│ ├── publish-Frames.podspec.yml
│ ├── run-regression-tests.yml
│ └── validate-for-app-store.yml
├── .gitignore
├── .jazzy.yaml
├── .jazzy
└── .themes
│ └── checkout.com
│ ├── assets
│ ├── css
│ │ ├── highlight.css.scss
│ │ └── jazzy.css.scss
│ ├── img
│ │ ├── carat.png
│ │ ├── dash.png
│ │ └── spinner.gif
│ └── js
│ │ ├── jazzy.js
│ │ ├── jazzy.search.js
│ │ ├── jquery.min.js
│ │ ├── lunr.min.js
│ │ └── typeahead.jquery.js
│ └── templates
│ ├── deprecation.mustache
│ ├── doc.mustache
│ ├── footer.mustache
│ ├── header.mustache
│ ├── nav.mustache
│ ├── parameter.mustache
│ ├── task.mustache
│ └── tasks.mustache
├── .swiftlint.yml
├── .swiftpm
└── xcode
│ ├── package.xcworkspace
│ └── contents.xcworkspacedata
│ └── xcshareddata
│ └── xcschemes
│ ├── CheckoutTests.xcscheme
│ ├── Frames.xcscheme
│ └── FramesTests.xcscheme
├── Checkout.podspec
├── Checkout
├── .gitignore
├── .swiftlint.yml
├── .swiftpm
│ └── xcode
│ │ ├── package.xcworkspace
│ │ └── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ └── xcschemes
│ │ └── Checkout.xcscheme
├── Samples
│ ├── CocoapodsSample
│ │ ├── CheckoutCocoapodsSample.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata
│ │ │ │ └── xcschemes
│ │ │ │ └── CheckoutCocoapodsSample.xcscheme
│ │ ├── Podfile
│ │ └── Podfile.lock
│ ├── Package.swift
│ ├── SPMSample
│ │ └── CheckoutSPMSample.xcodeproj
│ │ │ ├── project.pbxproj
│ │ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── CheckoutSPMSample.xcscheme
│ └── Sample
│ │ └── Source
│ │ ├── 3DS
│ │ ├── ThreeDSViewController.swift
│ │ ├── ThreeDSViewController.xib
│ │ └── WebViewController.swift
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ │ ├── Card Tokenisation
│ │ ├── Buttons Table View Cell
│ │ │ ├── ButtonsTableViewCell.swift
│ │ │ └── ButtonsTableViewCell.xib
│ │ ├── Card Details
│ │ │ ├── CardDetailsTableViewCell.swift
│ │ │ ├── CardDetailsTableViewCell.xib
│ │ │ ├── ExpirationDatePicker.swift
│ │ │ └── NoTextEntryUITextFieldHelper.swift
│ │ ├── CardModel.swift
│ │ ├── CardNumberTextFieldDelegateHelper.swift
│ │ ├── CardTokenisationViewController+ViewModel.swift
│ │ ├── CardTokenizationViewController.swift
│ │ ├── CardTokenizationViewController.xib
│ │ ├── Saved Cards
│ │ │ ├── SavedCardTableViewCell.swift
│ │ │ ├── SavedCardTableViewCell.xib
│ │ │ ├── SavedCardsViewController.swift
│ │ │ └── SavedCardsViewController.xib
│ │ └── Select Scheme
│ │ │ ├── SelectSchemeViewController.swift
│ │ │ └── SelectSchemeViewController.xib
│ │ ├── Info.plist
│ │ ├── LaunchScreen.storyboard
│ │ ├── Main.storyboard
│ │ ├── SampleAppError.swift
│ │ ├── SceneDelegate.swift
│ │ ├── Timezone+utc.swift
│ │ ├── UIColor+CKO.swift
│ │ └── ViewController.swift
└── Source
│ ├── 3DSHandling
│ ├── ThreeDSError.swift
│ ├── ThreeDSWKNavigationHelper.swift
│ ├── ThreeDSWKNavigationHelperDelegate.swift
│ └── URLHelper.swift
│ ├── CardUtilities.swift
│ ├── CheckoutError.swift
│ ├── Extension
│ ├── Dictionary+Additions.swift
│ ├── Foundation+Extensions.swift
│ ├── NSRegularExpression+initStaticPattern.swift
│ ├── StringExtensions.swift
│ ├── TimeZone+constants.swift
│ ├── UIDevice+modelName.swift
│ └── URL+initStaticString.swift
│ ├── Logging
│ ├── AnyCodable.swift
│ ├── CheckoutLogEvent+Types.swift
│ ├── CheckoutLogEvent.swift
│ ├── DateProvider.swift
│ └── LogManager.swift
│ ├── Model
│ ├── Address.swift
│ ├── Card+Scheme.swift
│ ├── Card.swift
│ ├── Country.swift
│ ├── Environment.swift
│ ├── ExpiryDate.swift
│ ├── PaymentSource.swift
│ ├── Phone.swift
│ └── TokenDetails.swift
│ ├── Models
│ └── ApplePay.swift
│ ├── Network
│ ├── Error
│ │ └── NetworkError.swift
│ ├── Models
│ │ ├── NetworkRequestResult.swift
│ │ ├── SecurityCode
│ │ │ ├── SecurityCodeError.swift
│ │ │ ├── SecurityCodeRequest.swift
│ │ │ └── SecurityCodeResponse.swift
│ │ ├── TokenRequest.swift
│ │ └── TokenResponse.swift
│ ├── NetworkManager.swift
│ └── RequestFactory.swift
│ ├── Protocols
│ ├── CalendarProtocol.swift
│ ├── DateProviding.swift
│ ├── Decoding.swift
│ ├── DeviceInformationProviding.swift
│ └── Encoding.swift
│ ├── Tokenisation
│ ├── CheckoutAPIService.swift
│ ├── Error
│ │ ├── TokenisationError+ServerError.swift
│ │ ├── TokenisationError+TokenRequest.swift
│ │ └── TokenisationError.swift
│ ├── TokenDetailsFactory.swift
│ └── TokenRequestFactory.swift
│ └── Validation
│ ├── Constants.swift
│ ├── Error
│ ├── ValidationError+Address.swift
│ ├── ValidationError+CVV.swift
│ ├── ValidationError+Card.swift
│ ├── ValidationError+CardNumber.swift
│ ├── ValidationError+EagerCardNumber.swift
│ ├── ValidationError+ExpiryDate.swift
│ ├── ValidationError+Phone.swift
│ └── ValidationError.swift
│ ├── LuhnChecker.swift
│ ├── ValidationResult.swift
│ └── Validators
│ ├── AddressValidator.swift
│ ├── CVVValidator.swift
│ ├── CardNumberValidator.swift
│ ├── CardValidator.swift
│ └── PhoneValidator.swift
├── CheckoutTests
├── 3DSHandling
│ ├── ThreeDSErrorTests.swift
│ ├── ThreeDSWKNavigationHelperTests.swift
│ └── URLHelperTests.swift
├── CheckoutErrorTests.swift
├── Extension
│ ├── Dictionary+AdditionsTests.swift
│ ├── StringExtensionsTests.swift
│ └── TimeZone+constantsTests.swift
├── Integration
│ ├── CardValidatorIntegrationTests.swift
│ └── CheckoutAPIServiceIntegrationTests.swift
├── Logging
│ ├── CheckoutLogEventTests.swift
│ ├── DateProviderTests.swift
│ └── LogManagerTests.swift
├── Model
│ ├── CardSchemeTests.swift
│ ├── CountryTests.swift
│ └── EnvironmentTests.swift
├── Network
│ ├── Error
│ │ └── NetworkErrorTests.swift
│ ├── NetworkManagerTests.swift
│ └── RequestFactoryTests.swift
├── Stubs
│ ├── StubAddressValidator.swift
│ ├── StubAnyCodable.swift
│ ├── StubBaseURLProvider.swift
│ ├── StubCVVValidator.swift
│ ├── StubCalendar.swift
│ ├── StubCardNumberValidator.swift
│ ├── StubCardValidator.swift
│ ├── StubCheckoutEventLogger.swift
│ ├── StubDateProvider.swift
│ ├── StubDecoder.swift
│ ├── StubDeviceInformationProvider.swift
│ ├── StubEncoder.swift
│ ├── StubError.swift
│ ├── StubLogManager.swift
│ ├── StubLuhnChecker.swift
│ ├── StubPhoneValidator.swift
│ ├── StubProvider.swift
│ ├── StubRequestExecutor.swift
│ ├── StubRequestFactory.swift
│ ├── StubRisk.swift
│ ├── StubSingleValueEncodingContainer.swift
│ ├── StubThreeDSWKNavigationHelperDelegate.swift
│ ├── StubTokenDetailsFactory.swift
│ ├── StubTokenRequestFactory.swift
│ ├── StubURLHelper.swift
│ ├── StubURLSession.swift
│ ├── StubURLSessionDataTask.swift
│ └── StubWKNavigationAction.swift
├── Tokenisation
│ ├── CheckoutAPIServiceTests.swift
│ ├── TokenDetailsFactoryTests.swift
│ └── TokenRequestFactoryTests.swift
└── Validation
│ ├── AddressValidatorTests.swift
│ ├── CVVValidatorTests.swift
│ ├── CardNumberValidatorTests.swift
│ ├── CardValidatorTests.swift
│ ├── LuhnCheckerTests.swift
│ └── PhoneValidatorTests.swift
├── Frames.podspec
├── LICENSE
├── Package.resolved
├── Package.swift
├── README.md
├── Source
├── CardUtils.swift
├── CheckoutColor.swift
├── CheckoutSdkIos.swift
├── Core
│ ├── CheckoutAPIService.swift
│ ├── Constants+SchemeIcon.swift
│ ├── Constants
│ │ ├── AccessibilityIdentifiers.swift
│ │ ├── Constants+LocalizationKeys.swift
│ │ ├── Constants+Padding.swift
│ │ ├── Constants+Style.swift
│ │ └── Constants.swift
│ ├── ContentTypeProviding.swift
│ ├── Dispatching.swift
│ ├── Environment.swift
│ ├── Logging
│ │ ├── CorrelationIDGenerator.swift
│ │ ├── DateProvider.swift
│ │ ├── FramesEventLogger.swift
│ │ ├── FramesLogEvent.swift
│ │ ├── PropertyProviding.swift
│ │ └── RemoteProcessorMetadata+extensions.swift
│ ├── Models
│ │ ├── CardScheme.swift
│ │ ├── SecurityCodeTokenDetails.swift
│ │ └── Typealiases.swift
│ ├── ThreeDSWKNavigationHelperFactory.swift
│ ├── TopLevelDecoder.swift
│ └── TopLevelEncoder.swift
├── Extensions
│ ├── CAShapeLayerExtension.swift
│ ├── Dictionary+Additions.swift
│ ├── DispatchQueue+Dispatching.swift
│ ├── JSONDecoder+TopLevelDecoder.swift
│ ├── JSONEncoder+ContentTypeProviding.swift
│ ├── JSONEncoder+TopLevelEncoder.swift
│ ├── PhoneExtensions.swift
│ ├── StringExtensions.swift
│ ├── UIBarStyle+stringValue.swift
│ ├── UIBezierPathExtension.swift
│ ├── UIDeviceExtensions.swift
│ ├── UIFont+PropertyProviding.swift
│ ├── UINavigationControllerExtensions.swift
│ ├── UIResponderExtensions.swift
│ ├── UIStackViewExtension.swift
│ ├── UITableViewExtensions.swift
│ ├── UITextFieldExtension.swift
│ ├── UIViewControllerExtensions.swift
│ ├── UIViewExtensions.swift
│ └── URL+Extensions.swift
├── Resources
│ ├── Images.xcassets
│ │ ├── Contents.json
│ │ ├── Scheme
│ │ │ ├── Contents.json
│ │ │ ├── icon-amex.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-amex.pdf
│ │ │ ├── icon-blank.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-blank.pdf
│ │ │ ├── icon-diners.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-diners.pdf
│ │ │ ├── icon-discover.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-discover.pdf
│ │ │ ├── icon-jcb.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-jcb.pdf
│ │ │ ├── icon-mada.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-mada.pdf
│ │ │ ├── icon-maestro.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-maestro.pdf
│ │ │ ├── icon-mastercard.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-mastercard.pdf
│ │ │ └── icon-visa.imageset
│ │ │ │ ├── Contents.json
│ │ │ │ └── icon-visa.pdf
│ │ ├── arrow_blue_right.imageset
│ │ │ ├── Contents.json
│ │ │ └── arrow_blue_right.pdf
│ │ ├── keyboard-next.imageset
│ │ │ ├── Contents.json
│ │ │ ├── keyboard-next@2x.png
│ │ │ └── keyboard-next@3x.png
│ │ ├── keyboard-previous.imageset
│ │ │ ├── Contents.json
│ │ │ ├── keyboard-previous@2x.png
│ │ │ └── keyboard-previous@3x.png
│ │ ├── left_arrow.imageset
│ │ │ ├── Contents.json
│ │ │ └── left_arrow.pdf
│ │ └── warning.imageset
│ │ │ ├── Contents.json
│ │ │ └── warning.pdf
│ ├── PrivacyInfo.xcprivacy
│ ├── ar.lproj
│ │ └── Localizable.strings
│ ├── de.lproj
│ │ └── Localizable.strings
│ ├── en.lproj
│ │ └── Localizable.strings
│ ├── es.lproj
│ │ └── Localizable.strings
│ ├── fr.lproj
│ │ └── Localizable.strings
│ ├── it.lproj
│ │ └── Localizable.strings
│ ├── nl.lproj
│ │ └── Localizable.strings
│ └── ro.lproj
│ │ └── Localizable.strings
├── Suppporting Files
│ ├── CheckoutSdkIos.h
│ └── Info.plist
└── UI
│ ├── 3DS
│ ├── ThreedsWebViewController.swift
│ └── ThreedsWebViewControllerDelegate.swift
│ ├── BillingForm
│ ├── BillingFormCell.swift
│ ├── Default Implementation
│ │ ├── BillingForm
│ │ │ ├── Fields
│ │ │ │ ├── AddressLine1
│ │ │ │ │ └── DefaultBillingFormAddressLine1CellStyle.swift
│ │ │ │ ├── AddressLine2
│ │ │ │ │ └── DefaultBillingFormAddressLine2CellStyle.swift
│ │ │ │ ├── City
│ │ │ │ │ └── DefaultBillingFormCityCellStyle.swift
│ │ │ │ ├── Country
│ │ │ │ │ └── DefaultBillingFormCountryCellStyle.swift
│ │ │ │ ├── FullName
│ │ │ │ │ └── DefaultBillingFormFullNameCellStyle.swift
│ │ │ │ ├── PhoneNumber
│ │ │ │ │ └── DefaultBillingFormPhoneNumberCellStyle.swift
│ │ │ │ ├── Postcode
│ │ │ │ │ └── DefaultBillingFormPostCodeCellStyle.swift
│ │ │ │ └── State
│ │ │ │ │ └── DefaultBillingFormStateCellStyle.swift
│ │ │ ├── Header
│ │ │ │ ├── Cancel
│ │ │ │ │ └── DefaultCancelButtonFormStyle.swift
│ │ │ │ ├── Done
│ │ │ │ │ └── DefaultDoneFormButtonStyle.swift
│ │ │ │ ├── Main
│ │ │ │ │ └── DefaultBillingFormHeaderCellStyle.swift
│ │ │ │ └── Title
│ │ │ │ │ └── DefaultHeaderLabelFormStyle.swift
│ │ │ └── Main
│ │ │ │ └── DefaultBillingFormStyle.swift
│ │ └── Elements
│ │ │ ├── Country
│ │ │ └── DefaultCountryFormButtonStyle.swift
│ │ │ ├── DefaultBorderStyle.swift
│ │ │ ├── Error
│ │ │ └── DefaultErrorInputLabelStyle.swift
│ │ │ ├── Hint
│ │ │ └── DefaultHintInputLabelStyle.swift
│ │ │ ├── TextField
│ │ │ └── DefaultTextField.swift
│ │ │ └── Title
│ │ │ └── DefaultTitleLabelStyle.swift
│ ├── FramesFactory.swift
│ ├── Model
│ │ └── BillingForm.swift
│ ├── Style Protocol
│ │ ├── BillingFormHeaderCellStyle.swift
│ │ └── BillingFormStyle.swift
│ ├── View
│ │ ├── BillingFormCellTextField.swift
│ │ ├── BillingFormHeaderCell.swift
│ │ ├── BillingFormTextField.swift
│ │ ├── BillingFormTextFieldView.swift
│ │ └── MainBillingFormTextField.swift
│ ├── ViewController
│ │ └── BillingFormViewController.swift
│ └── ViewModel
│ │ ├── BillingFormViewModel.swift
│ │ └── DefaultBillingFormViewModel.swift
│ ├── CommonUI
│ ├── Protocols
│ │ ├── Cell
│ │ │ ├── CellButtonStyle.swift
│ │ │ ├── CellStyle.swift
│ │ │ └── CellTextFieldStyle.swift
│ │ └── Elements
│ │ │ ├── ElementBorderStyle.swift
│ │ │ ├── ElementButtonStyle.swift
│ │ │ ├── ElementErrorViewStyle.swift
│ │ │ ├── ElementStyle.swift
│ │ │ └── ElementTextFieldStyle.swift
│ ├── UIStyle
│ │ ├── FramesUIStyle+UIColor.swift
│ │ └── FramesUIStyle+UIFont.swift
│ └── View
│ │ ├── Component
│ │ ├── BorderView.swift
│ │ ├── InputView.swift
│ │ ├── SelectionButtonView.swift
│ │ └── SimpleErrorView.swift
│ │ ├── Core
│ │ ├── ButtonView.swift
│ │ ├── ImageContainerView.swift
│ │ ├── LabelView.swift
│ │ ├── SecureDisplayView.swift
│ │ └── TextFieldView.swift
│ │ └── TableViewCell
│ │ └── SelectionButtonTableViewCell.swift
│ ├── CountrySelection
│ ├── CountrySelectionViewController.swift
│ └── CountrySelectionViewControllerDelegate.swift
│ ├── PaymentForm
│ ├── Default Implementation
│ │ ├── BillingFormSummary
│ │ │ └── Summary
│ │ │ │ ├── Button
│ │ │ │ ├── DefaultAddBillingDetailsButtonStyle.swift
│ │ │ │ └── DefaultEditBillingDetailsButtonStyle.swift
│ │ │ │ └── View
│ │ │ │ ├── DefaultAddBillingDetailsViewStyle.swift
│ │ │ │ └── DefaultBillingSummaryViewStyle.swift
│ │ ├── CardNumber
│ │ │ └── DefaultCardNumberFormStyle.swift
│ │ ├── Cardholder
│ │ │ └── DefaultCardholderFormStyle.swift
│ │ ├── DefaultPayButtonFormStyle.swift
│ │ ├── DefaultPaymentFormStyle.swift
│ │ ├── DefaultPaymentHeaderCellStyle.swift
│ │ ├── ExpiryDate
│ │ │ └── DefaultExpiryDateFormStyle.swift
│ │ └── SecurityCode
│ │ │ └── DefaultSecurityCodeFormStyle.swift
│ ├── Factory
│ │ └── PaymentFormFactory.swift
│ ├── Model
│ │ ├── PaymentFormConfiguration.swift
│ │ └── PaymentStyle.swift
│ ├── StyleProtocol
│ │ ├── BillingSummaryViewStyle.swift
│ │ ├── PaymentFormStyle.swift
│ │ └── PaymentHeaderCellStyle.swift
│ ├── View
│ │ ├── BillingFormSummaryView.swift
│ │ ├── CardNumber
│ │ │ ├── CardNumberView.swift
│ │ │ └── CardNumberViewModel.swift
│ │ ├── CardholderName
│ │ │ ├── CardholderView.swift
│ │ │ └── CardholderViewModel.swift
│ │ ├── ExpiryDate
│ │ │ ├── ExpiryDateFormatter.swift
│ │ │ └── ExpiryDateView.swift
│ │ ├── PaymentHeaderView.swift
│ │ ├── SecurityCodeView.swift
│ │ └── SecurityCodeViewModel.swift
│ ├── ViewController
│ │ └── FramesPaymentViewController.swift
│ └── ViewModel
│ │ ├── CardCreationModel.swift
│ │ ├── DefaultPaymentViewModel.swift
│ │ └── PaymentViewModel.swift
│ ├── SecurityCodeComponent
│ ├── DefaultSecurityCodeFormStyle+Extension.swift
│ ├── SecurityCodeComponent.swift
│ ├── SecurityCodeComponentConfiguration.swift
│ └── SecurityCodeComponentStyle.swift
│ ├── Theme
│ ├── BillingForm
│ │ ├── Theme+BillingCountryInput.swift
│ │ ├── Theme+BillingForm.swift
│ │ ├── Theme+BillingHeader.swift
│ │ └── Theme+BillingInput.swift
│ ├── Generic
│ │ ├── Theme+Border.swift
│ │ ├── Theme+Button.swift
│ │ ├── Theme+Error.swift
│ │ ├── Theme+Mandatory.swift
│ │ ├── Theme+PageHeaderTitle.swift
│ │ ├── Theme+Subtitle.swift
│ │ ├── Theme+TextField.swift
│ │ └── Theme+Title.swift
│ ├── PaymentForm
│ │ ├── Theme+AddBillingSectionButton.swift
│ │ ├── Theme+BillingSummary.swift
│ │ ├── Theme+CardNumberSection.swift
│ │ ├── Theme+PayButton.swift
│ │ ├── Theme+PaymentFormStyle.swift
│ │ ├── Theme+PaymentHeader.swift
│ │ └── Theme+PaymentHeaderSubtitle.swift
│ └── Theme.swift
│ └── Validator
│ ├── GenericInputValidator.swift
│ ├── PhoneNumberValidator.swift
│ └── Validator.swift
├── Tests
├── Core
│ ├── CardSchemeTests.swift
│ ├── CardUtilsTests.swift
│ ├── Extensions
│ │ ├── CAShapeLayerExtensionTests.swift
│ │ ├── ConstantsSchemeIconTests.swift
│ │ ├── Dictionary+AdditionsTests.swift
│ │ ├── DispatchQueue+DispatchingTests.swift
│ │ ├── PhoneExtensionTests.swift
│ │ ├── UIBarStyleTests.swift
│ │ ├── UIBezierPathExtensionTests.swift
│ │ ├── UIFont+PropertyProvidingTests.swift
│ │ ├── UINavigationControllerTests.swift
│ │ ├── UITextField+ExtensionsTests.swift
│ │ └── URL+ExtensionsTests.swift
│ └── Logging
│ │ ├── CorrelationIDGeneratorTests.swift
│ │ ├── FramesEventLoggerTests.swift
│ │ └── FramesLogEventTests.swift
├── Fixtures
│ ├── applePayToken.json
│ ├── applePayTokenInvalid.json
│ ├── cardProviders.json
│ ├── cardToken.json
│ ├── cardTokenBillingDetails.json
│ └── cardTokenInvalidNumber.json
├── Info.plist
├── Mocks
│ ├── BillingFormTableViewMockDelegate.swift
│ ├── BillingFormTextFieldCellMockDelegate.swift
│ ├── BillingFormViewControllerMockDelegate.swift
│ ├── BillingFormViewModelEditingMockDelegate.swift
│ ├── BillingFormViewModelMockDelegate.swift
│ ├── CvvInputViewMockDelegate.swift
│ ├── MockCardNumberViewModel.swift
│ ├── MockCardNumberViewModelDelegate.swift
│ ├── MockCardValidator.swift
│ ├── MockCardholderDelegate.swift
│ ├── MockExpiryDateViewDelegate.swift
│ ├── MockSecurityCodeDelegate.swift
│ ├── MockThreeDSWKNavigationHelper.swift
│ ├── MockThreeDSWKNavigationHelperFactory.swift
│ ├── NavigationControllerMock.swift
│ ├── NotificationCenterMock.swift
│ ├── PaymentViewControllerMockDelegate.swift
│ ├── StubCheckoutAPIService.swift
│ ├── StubCheckoutEventLogger.swift
│ ├── StubCorrelationIDGenerator.swift
│ ├── StubDateProvider.swift
│ ├── StubDispatcher.swift
│ ├── StubError.swift
│ ├── StubFramesEventLogger.swift
│ ├── StubJSONDecoder.swift
│ ├── StubJSONEncoder.swift
│ ├── StubUIDevice.swift
│ ├── StubURLProtocol.swift
│ ├── StubURLSession.swift
│ └── StubURLSessionDataTask.swift
├── Resources
│ ├── ColorTests.swift
│ └── ResourcesTests.swift
└── UI
│ ├── 3DS
│ └── ThreedsWebViewControllerTests.swift
│ ├── BillingForm
│ ├── Validator
│ │ ├── GenericInputValidatorTests.swift
│ │ └── PhoneNumberValidatorTests.swift
│ ├── View
│ │ ├── BillingFormButtonViewTests.swift
│ │ ├── BillingFormFullNameTextFieldCellTests.swift
│ │ ├── BillingFormSummaryViewTests.swift
│ │ ├── BillingFormTextFieldErrorViewTests.swift
│ │ ├── BillingFormTextFieldViewTests.swift
│ │ ├── ExpiryDateFormatterTests.swift
│ │ ├── ExpiryDateViewTests.swift
│ │ ├── MirrorObject.swift
│ │ ├── SecureDisplayViewTests.swift
│ │ ├── SecurityCodeViewModelTests.swift
│ │ ├── SecurityCodeViewTests.swift
│ │ └── TextFieldViewTests.swift
│ ├── ViewController
│ │ └── BillingFormViewControllerTests.swift
│ └── ViewModel
│ │ ├── BillingFormCellTypeTests.swift
│ │ ├── BillingFormViewModelTests.swift
│ │ ├── CardCreationModelTests.swift
│ │ └── PaymentViewModelTests.swift
│ ├── CommonUI
│ └── BorderViewTest.swift
│ ├── CountrySelection
│ └── CountrySelectionViewControllerTests.swift
│ ├── Extension
│ ├── UIStackViewExtensionTests.swift
│ └── UIViewExtensionTests.swift
│ ├── Factory
│ └── FramesFactoryTests.swift
│ ├── FramesUIStyle
│ ├── FramesUIStyleColorTests.swift
│ └── FramesUIStyleFontTests.swift
│ ├── PaymentForm
│ ├── CardNumber
│ │ ├── CardNumberViewModelTests.swift
│ │ └── CardNumberViewTests.swift
│ ├── CardholderViewModelTests.swift
│ └── PaymentViewControllerTests.swift
│ └── SecurityCodeComponent
│ └── SecurityCodeComponentTests.swift
├── iOS Example Frame SPM
├── ExportOptions.plist
├── Package.swift
├── iOS Example Frame Regression Tests
│ ├── CardSchemeFormatSnapshotTests.swift
│ ├── CardTypeTokenCreationTests.swift
│ ├── CardValidationSnapshotTests.swift
│ ├── CardValidationTests.swift
│ ├── ExpiryDateEdgeCaseTests.swift
│ ├── Helpers
│ │ ├── Helper.swift
│ │ ├── Language.swift
│ │ ├── StaticTexts.swift
│ │ ├── TestCard.swift
│ │ ├── XCUIApplication+TestHelpers.swift
│ │ └── XCUIElement+TestHelpers.swift
│ └── __Snapshots__
│ │ ├── CardSchemeFormatSnapshotTests
│ │ ├── testCardFormatting.1.png
│ │ ├── testCardFormatting.10.png
│ │ ├── testCardFormatting.11.png
│ │ ├── testCardFormatting.2.png
│ │ ├── testCardFormatting.3.png
│ │ ├── testCardFormatting.4.png
│ │ ├── testCardFormatting.5.png
│ │ ├── testCardFormatting.6.png
│ │ ├── testCardFormatting.7.png
│ │ ├── testCardFormatting.8.png
│ │ └── testCardFormatting.9.png
│ │ └── CardValidationSnapshotTests
│ │ ├── testCardNumber_Failure.1.png
│ │ ├── testCardNumber_Failure.2.png
│ │ ├── testCardNumber_Failure.3.png
│ │ ├── testCardNumber_Failure.4.png
│ │ ├── testCardNumber_Failure.5.png
│ │ ├── testCardNumber_Failure.6.png
│ │ ├── testCardNumber_Failure.7.png
│ │ ├── testCardNumber_Failure.8.png
│ │ ├── testCardNumber_Success.1.png
│ │ ├── testSecurityCode_Failure.1.png
│ │ ├── testSecurityCode_Failure.2.png
│ │ ├── testSecurityCode_Failure.3.png
│ │ ├── testSecurityCode_Failure.4.png
│ │ ├── testSecurityCode_Failure.5.png
│ │ ├── testSecurityCode_Failure.6.png
│ │ ├── testSecurityCode_Failure.7.png
│ │ ├── testSecurityCode_Failure.8.png
│ │ ├── testSecurityCode_Success.1.png
│ │ ├── test_ExpiryDate_InThePast_Failure.1.png
│ │ ├── test_ExpiryDate_InThePast_Failure.2.png
│ │ ├── test_ExpiryDate_InThePast_Failure.3.png
│ │ ├── test_ExpiryDate_InThePast_Failure.4.png
│ │ ├── test_ExpiryDate_InThePast_Failure.5.png
│ │ ├── test_ExpiryDate_InThePast_Failure.6.png
│ │ ├── test_ExpiryDate_InThePast_Failure.7.png
│ │ ├── test_ExpiryDate_InThePast_Failure.8.png
│ │ ├── test_ExpiryDate_Invalid_Failure.1.png
│ │ ├── test_ExpiryDate_Invalid_Failure.2.png
│ │ ├── test_ExpiryDate_Invalid_Failure.3.png
│ │ ├── test_ExpiryDate_Invalid_Failure.4.png
│ │ ├── test_ExpiryDate_Invalid_Failure.5.png
│ │ ├── test_ExpiryDate_Invalid_Failure.6.png
│ │ ├── test_ExpiryDate_Invalid_Failure.7.png
│ │ ├── test_ExpiryDate_Invalid_Failure.8.png
│ │ └── test_ExpiryDate_Success.1.png
└── iOS Example Frame SPM.xcodeproj
│ ├── project.pbxproj
│ └── xcshareddata
│ └── xcschemes
│ ├── Regression Tests.xcscheme
│ ├── UITest.xcscheme
│ └── iOS Example Frame.xcscheme
└── iOS Example Frame
├── Package.swift
├── Podfile
├── Podfile.lock
├── iOS Example Frame.xcodeproj
├── project.pbxproj
└── xcshareddata
│ └── xcschemes
│ └── iOS Example Frame.xcscheme
├── iOS Example Frame
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── 100.png
│ │ ├── 1024.png
│ │ ├── 114.png
│ │ ├── 120.png
│ │ ├── 144.png
│ │ ├── 152.png
│ │ ├── 167.png
│ │ ├── 180.png
│ │ ├── 20.png
│ │ ├── 29.png
│ │ ├── 40.png
│ │ ├── 50.png
│ │ ├── 57.png
│ │ ├── 58.png
│ │ ├── 60.png
│ │ ├── 72.png
│ │ ├── 76.png
│ │ ├── 80.png
│ │ ├── 87.png
│ │ └── Contents.json
│ ├── Contents.json
│ ├── amex-icon.imageset
│ │ ├── Contents.json
│ │ └── amex-icon.pdf
│ ├── apple-pay.imageset
│ │ ├── Contents.json
│ │ └── apple-pay.pdf
│ ├── arrow_blue_right.imageset
│ │ ├── Contents.json
│ │ └── arrow_blue_right.pdf
│ ├── arrow_green_down.imageset
│ │ ├── Contents.json
│ │ └── arrow_green_down.pdf
│ ├── checkout-logo.imageset
│ │ ├── Contents.json
│ │ └── checkout-logo.pdf
│ ├── cloud-key.imageset
│ │ ├── Contents.json
│ │ └── cloud.png
│ ├── diners-icon.imageset
│ │ ├── Contents.json
│ │ └── diners-icon.pdf
│ ├── discover-icon.imageset
│ │ ├── Contents.json
│ │ └── discover-icon.pdf
│ ├── jcb-icon.imageset
│ │ ├── Contents.json
│ │ └── jcb-icon.pdf
│ ├── keyboard-next.imageset
│ │ ├── Contents.json
│ │ └── keyboard-next@3x.png
│ ├── keyboard-previous-1.imageset
│ │ ├── Contents.json
│ │ └── keyboard-previous@2x.png
│ ├── keyboard-previous.imageset
│ │ ├── Contents.json
│ │ └── keyboard-previous@2x.png
│ ├── mada-icon.imageset
│ │ ├── Contents.json
│ │ └── mada-icon.pdf
│ ├── maestro-icon.imageset
│ │ ├── Contents.json
│ │ └── maestro-icon.pdf
│ ├── mastercard-icon.imageset
│ │ ├── Contents.json
│ │ └── mastercard-icon.pdf
│ ├── new-experince.imageset
│ │ ├── Contents.json
│ │ └── new.pdf
│ ├── old-experince.imageset
│ │ ├── Contents.json
│ │ └── old.pdf
│ ├── visa-icon.imageset
│ │ ├── Contents.json
│ │ └── visa-icon.pdf
│ └── warning.imageset
│ │ ├── Contents.json
│ │ └── warning.pdf
├── Data
│ └── example_apple_pay_payment_data.json
├── Extension
│ ├── UIViewControllerExtension.swift
│ └── UIViewExtension.swift
├── Factory
│ ├── Factory+UITest.swift
│ └── Factory.swift
├── Helper
│ └── ApplePayCreator.swift
├── Info.plist
├── Resources
│ ├── Fonts
│ │ ├── Graphik
│ │ │ ├── GraphikLCG-Black.otf
│ │ │ ├── GraphikLCG-BlackItalic.otf
│ │ │ ├── GraphikLCG-Bold.otf
│ │ │ ├── GraphikLCG-BoldItalic.otf
│ │ │ ├── GraphikLCG-Extralight.otf
│ │ │ ├── GraphikLCG-ExtralightItalic.otf
│ │ │ ├── GraphikLCG-Light.otf
│ │ │ ├── GraphikLCG-LightItalic.otf
│ │ │ ├── GraphikLCG-Medium.otf
│ │ │ ├── GraphikLCG-MediumItalic.otf
│ │ │ ├── GraphikLCG-Regular.otf
│ │ │ ├── GraphikLCG-RegularItalic.otf
│ │ │ ├── GraphikLCG-Semibold.otf
│ │ │ ├── GraphikLCG-SemiboldItalic.otf
│ │ │ ├── GraphikLCG-Super.otf
│ │ │ ├── GraphikLCG-SuperItalic.otf
│ │ │ ├── GraphikLCG-Thin.otf
│ │ │ └── GraphikLCG-ThinItalic.otf
│ │ ├── Roboto
│ │ │ ├── Apache License.txt
│ │ │ ├── Roboto-Black.ttf
│ │ │ ├── Roboto-BlackItalic.ttf
│ │ │ ├── Roboto-Bold.ttf
│ │ │ ├── Roboto-BoldItalic.ttf
│ │ │ ├── Roboto-Italic.ttf
│ │ │ ├── Roboto-Light.ttf
│ │ │ ├── Roboto-LightItalic.ttf
│ │ │ ├── Roboto-Medium.ttf
│ │ │ ├── Roboto-MediumItalic.ttf
│ │ │ ├── Roboto-Regular.ttf
│ │ │ ├── Roboto-Thin.ttf
│ │ │ └── Roboto-ThinItalic.ttf
│ │ ├── SF-Mono
│ │ │ ├── SF-Mono-Bold.otf
│ │ │ ├── SF-Mono-BoldItalic.otf
│ │ │ ├── SF-Mono-Heavy.otf
│ │ │ ├── SF-Mono-HeavyItalic.otf
│ │ │ ├── SF-Mono-Light.otf
│ │ │ ├── SF-Mono-LightItalic.otf
│ │ │ ├── SF-Mono-Medium.otf
│ │ │ ├── SF-Mono-MediumItalic.otf
│ │ │ ├── SF-Mono-Regular.otf
│ │ │ ├── SF-Mono-RegularItalic.otf
│ │ │ ├── SF-Mono-Semibold.otf
│ │ │ └── SF-Mono-SemiboldItalic.otf
│ │ ├── UIFont+Graphik.swift
│ │ ├── UIFont+Roboto.swift
│ │ └── UIFont+SFMono.swift
│ ├── ar.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── de.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── en.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── es.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── fr.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── it.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ ├── nl.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ └── ro.lproj
│ │ └── LaunchScreen.strings
├── Storyboards
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── ar-001.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
│ └── ar.lproj
│ │ ├── LaunchScreen.strings
│ │ └── Main.strings
├── Style
│ ├── CustomStyle1.swift
│ ├── Style.swift
│ ├── ThemeDemo+Border.swift
│ └── ThemeDemo.swift
├── ViewController
│ ├── HomeViewController.swift
│ └── SecurityCodeViewController.swift
└── ar.lproj
│ ├── LaunchScreen.strings
│ └── Main.strings
└── iOS Example FrameUITests
├── FrameUITests.swift
├── Helpers
├── XCUIApplication+Extension.swift
└── XCUIElement+TestHelpers.swift
└── SecurityCodeComponentUITests.swift
/.github/CODEOWNERS.md:
--------------------------------------------------------------------------------
1 | # The iOS mobile team owns and maintains this project.
2 | * @checkout/mobile-ios
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | Before you open an issue, please check if a similar issue already exists or has been closed before.
2 |
3 | ### When reporting a bug, please be sure to include the following:
4 |
5 | * [ ] A descriptive title
6 | * [ ] An _isolated_ way to reproduce the behavior (example: GitHub repository with code isolated to the issue that anyone can clone to observe the problem)
7 | * [ ] What version of `FramesIos` you're using, and the platform(s) you're running it on
8 | * [ ] The behavior you expect to see, and the actual behavior
9 |
10 | ### When you open an issue for a feature request, please add as much detail as possible:
11 |
12 | * [ ] A descriptive title
13 | * [ ] A description of the problem you're trying to solve, including _why_ you think this is a problem
14 | * [ ] An overview of the suggested solution
15 | * [ ] If the feature changes current behavior, reasons why your solution is better
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **To Reproduce**
11 | Steps to reproduce the behavior:
12 | 1. Go to '...'
13 | 2. Click on '....'
14 | 3. Scroll down to '....'
15 | 4. See error
16 |
17 | **Expected behavior**
18 | A clear and concise description of what you expected to happen.
19 |
20 | **Screenshots**
21 | If applicable, add screenshots to help explain your problem.
22 |
23 | **Desktop (please complete the following information):**
24 | - OS: [e.g. iOS]
25 | - Browser [e.g. chrome, safari]
26 | - Version [e.g. 22]
27 |
28 | **Smartphone (please complete the following information):**
29 | - Device: [e.g. iPhone6]
30 | - OS: [e.g. iOS8.1]
31 | - Browser [e.g. stock browser, safari]
32 | - Version [e.g. 22]
33 |
34 | **Additional context**
35 | Add any other context about the problem here.
36 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 |
5 | ---
6 |
7 | **Is your feature request related to a problem? Please describe.**
8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
9 |
10 | **Describe the solution you'd like**
11 | A clear and concise description of what you want to happen.
12 |
13 | **Describe alternatives you've considered**
14 | A clear and concise description of any alternative solutions or features you've considered.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleIdentifier
6 | com.jazzy.frames
7 | CFBundleName
8 | Frames
9 | DocSetPlatformFamily
10 | frames
11 | isDashDocset
12 |
13 | dashIndexFilePath
14 | index.html
15 | isJavaScriptEnabled
16 |
17 | DashDocSetFamily
18 | dashtoc
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/carat.png
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/dash.png
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/gh.png
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.docset/Contents/Resources/Documents/img/spinner.gif
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.docset/Contents/Resources/docSet.dsidx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.docset/Contents/Resources/docSet.dsidx
--------------------------------------------------------------------------------
/.github/docs/docsets/Frames.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/docsets/Frames.tgz
--------------------------------------------------------------------------------
/.github/docs/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/img/carat.png
--------------------------------------------------------------------------------
/.github/docs/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/img/dash.png
--------------------------------------------------------------------------------
/.github/docs/img/gh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/img/gh.png
--------------------------------------------------------------------------------
/.github/docs/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/docs/img/spinner.gif
--------------------------------------------------------------------------------
/.github/media/checkout-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/media/checkout-logo.png
--------------------------------------------------------------------------------
/.github/media/demo-frames-ios.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/media/demo-frames-ios.gif
--------------------------------------------------------------------------------
/.github/media/demo-frames-ios.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.github/media/demo-frames-ios.webp
--------------------------------------------------------------------------------
/.github/scripts/buildDocs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 |
4 | FRAMES_JSON=Frames.json
5 | CHECKOUT_JSON=Checkout.json
6 |
7 | # generate sourcekitten JSONs for modules
8 | echo "Parsing Frames"
9 | sourcekitten doc -- -workspace "iOS Example Frame/iOS Example Frame.xcworkspace" -scheme Frames -destination generic/platform=iOS > $FRAMES_JSON
10 |
11 | echo "Parsing Checkout"
12 | sourcekitten doc -- -workspace Checkout/Samples/CocoapodsSample/CheckoutCocoapodsSample.xcworkspace -scheme Checkout -destination generic/platform=iOS > $CHECKOUT_JSON
13 |
14 | # combine JSONs to build jazzy docs
15 | echo "Building docs"
16 | jazzy --sourcekitten-sourcefile $FRAMES_JSON,$CHECKOUT_JSON
17 |
18 | # cleanup JSONs
19 | echo "Cleaning up..."
20 | rm $FRAMES_JSON
21 | rm $CHECKOUT_JSON
22 |
23 | echo "Done!"
24 |
--------------------------------------------------------------------------------
/.github/scripts/lintEditedFiles.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -o pipefail
4 | git fetch origin main
5 | echo "Fetched"
6 |
7 | # Use a conditional to check if there are edited files
8 | if EDITED_FILES=$(git diff HEAD origin/main --name-only --diff-filter=d | grep "\.swift" | grep -v "\.swiftlint\.yml" | xargs echo | tr ' ' ','); then
9 | echo "Got edited files"
10 | echo $EDITED_FILES
11 |
12 | # Check if EDITED_FILES is empty or null
13 | if [ -z "$EDITED_FILES" ]; then
14 | echo "No edited .swift files found."
15 | else
16 | swiftlint lint $EDITED_FILES | sed -E -n 's/^(.*):([0-9]+):([0-9]+): error: (.*)/::error file=\1,line=\2,col=\3::\4\n\1:\2:\3/p'
17 | fi
18 | else
19 | echo "No changes in .swift files found."
20 | fi
21 |
--------------------------------------------------------------------------------
/.github/workflows/publish-Checkout.podspec.yml:
--------------------------------------------------------------------------------
1 | name: Publish Checkout.podspec
2 |
3 | on: workflow_dispatch
4 |
5 | jobs:
6 | publish:
7 | environment: CocoaPodsRelease
8 | runs-on: macos-15-xlarge
9 | steps:
10 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
11 |
12 | # - name: Check current branch
13 | # run: |
14 | # if [[ "${GITHUB_REF#refs/heads/}" != "main" && "${GITHUB_REF#refs/heads/}" != release/* ]]; then
15 | # echo "This workflow is expected to run on the main or release branch only."
16 | # exit 1
17 | # fi
18 |
19 | - name: Publish Checkout.podspec
20 | run: |
21 | gem install cocoapods
22 | pod trunk register mobilesdkteam@checkout.com
23 | pod trunk push Checkout.podspec --allow-warnings --verbose
24 | env:
25 | COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/publish-Frames.podspec.yml:
--------------------------------------------------------------------------------
1 | name: Publish Frames.podspec
2 |
3 | on: workflow_dispatch
4 |
5 | jobs:
6 | publish:
7 | environment: CocoaPodsRelease
8 | runs-on: macos-15-xlarge
9 | steps:
10 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
11 |
12 | # - name: Check current branch
13 | # run: |
14 | # if [[ "${GITHUB_REF#refs/heads/}" != "main" && "${GITHUB_REF#refs/heads/}" != release/* ]]; then
15 | # echo "This workflow is expected to run on the main or release branch only."
16 | # exit 1
17 | # fi
18 |
19 | - name: Publish Frames.podspec
20 | run: |
21 | gem install cocoapods
22 | pod trunk register mobilesdkteam@checkout.com
23 | pod trunk push --synchronous Frames.podspec --allow-warnings --verbose
24 | env:
25 | COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
26 |
--------------------------------------------------------------------------------
/.jazzy.yaml:
--------------------------------------------------------------------------------
1 | module: Frames
2 | author: Checkout.com
3 | author_url: https://www.checkout.com/
4 | source_host: github
5 | source_host_url: https://github.com/checkout/frames-ios
6 | source_host_files_url: https://github.com/checkout/frames-ios/tree/main
7 | output: .github/docs
8 | theme: .jazzy/.themes/checkout.com
9 | clean: true
10 | documentation: Documentation/**/*.md
11 | min_acl: public
12 | xcodebuild_arguments:
13 | - -workspace
14 | - iOS Example Frame/iOS Example Frame.xcworkspace
15 | - -scheme
16 | - Frames
17 | - -destination
18 | - generic/platform=iOS
19 |
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/assets/img/carat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.jazzy/.themes/checkout.com/assets/img/carat.png
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/assets/img/dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.jazzy/.themes/checkout.com/assets/img/dash.png
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/assets/img/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/.jazzy/.themes/checkout.com/assets/img/spinner.gif
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/templates/deprecation.mustache:
--------------------------------------------------------------------------------
1 | {{#deprecation_message}}
2 |
3 |
Deprecated
4 | {{{deprecation_message}}}
5 |
6 | {{/deprecation_message}}
7 | {{#unavailable_message}}
8 |
9 |
Unavailable
10 | {{{unavailable_message}}}
11 |
12 | {{/unavailable_message}}
13 |
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/templates/footer.mustache:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/templates/nav.mustache:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/templates/parameter.mustache:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{name}}
5 |
6 | |
7 |
8 |
9 | {{{discussion}}}
10 |
11 | |
12 |
13 |
--------------------------------------------------------------------------------
/.jazzy/.themes/checkout.com/templates/tasks.mustache:
--------------------------------------------------------------------------------
1 | {{#tasks.count}}
2 |
3 |
4 | {{#tasks}}
5 | {{> task}}
6 | {{/tasks}}
7 |
8 |
9 | {{/tasks.count}}
10 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Checkout.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'Checkout'
3 | s.version = '4.3.8'
4 | s.summary = 'Checkout SDK for iOS'
5 |
6 | s.description = <<-DESC
7 | Checkout Core functionality can only be used with the right level of PCI Compliance.
8 | Please contact us for more details.
9 | DESC
10 |
11 | s.homepage = 'https://github.com/checkout/frames-ios'
12 | s.license = { :type => 'MIT', :file => 'LICENSE' }
13 | s.author = { "Checkout.com Integration" => "integration@checkout.com" }
14 | s.source = { :git => "https://github.com/checkout/frames-ios.git", :tag => s.version }
15 |
16 | s.ios.deployment_target = '13.0'
17 | s.swift_version = "5.7"
18 |
19 | s.source_files = 'Checkout/Source/**/*.swift'
20 | s.exclude_files = "Checkout/Samples/**"
21 |
22 | s.dependency 'CheckoutEventLoggerKit', '~> 1.2.4'
23 | s.dependency 'Risk', '~> 3.0.2'
24 |
25 | end
26 |
--------------------------------------------------------------------------------
/Checkout/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .Trashes
3 | *.swp
4 |
5 | *.pbxuser
6 | xcuserdata/
7 |
8 | Pods/
9 |
10 |
11 | # SwiftLint Remote Config Cache
12 | .swiftlint/RemoteConfigCache
13 | Carthage/
14 |
--------------------------------------------------------------------------------
/Checkout/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | parent_config: https://raw.githubusercontent.com/raywenderlich/swift-style-guide/master/com.raywenderlich.swiftlint.yml
2 |
3 | nesting:
4 | type_level:
5 | warning: 2
6 | function_level:
7 | warning: 3
8 | cyclomatic_complexity:
9 | warning: 12
10 |
--------------------------------------------------------------------------------
/Checkout/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Checkout/Samples/CocoapodsSample/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, '13.0'
2 | install! 'cocoapods', :share_schemes_for_development_pods => true
3 |
4 | target 'CheckoutCocoapodsSample' do
5 | use_frameworks!
6 |
7 | # Pods for CheckoutSDKCocoapodsSample
8 | pod 'Checkout', '4.3.8'
9 | end
10 |
--------------------------------------------------------------------------------
/Checkout/Samples/CocoapodsSample/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Checkout (4.3.8):
3 | - CheckoutEventLoggerKit (~> 1.2.4)
4 | - Risk (~> 3.0.2)
5 | - CheckoutEventLoggerKit (1.2.4)
6 | - FingerprintPro (2.7.0)
7 | - Risk (3.0.4):
8 | - CheckoutEventLoggerKit (~> 1.2.4)
9 | - FingerprintPro (~> 2.7.0)
10 |
11 | DEPENDENCIES:
12 | - Checkout (= 4.3.8)
13 |
14 | SPEC REPOS:
15 | trunk:
16 | - Checkout
17 | - CheckoutEventLoggerKit
18 | - FingerprintPro
19 | - Risk
20 |
21 | SPEC CHECKSUMS:
22 | Checkout: 609314d0c54a079d4c0ddfcfa7011367a12f225a
23 | CheckoutEventLoggerKit: b780dec46295a34942780ea6230d0d5fd08aa05a
24 | FingerprintPro: 0c7dbd28fc83751ca64b06328e2fb22bbc7ed118
25 | Risk: 6c0fdbf826f741b028ec9158198404ce267d0d3e
26 |
27 | PODFILE CHECKSUM: 9b0372a870e3437a2232753690edfe8385c4d6e0
28 |
29 | COCOAPODS: 1.16.2
30 |
--------------------------------------------------------------------------------
/Checkout/Samples/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.6
2 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
3 | import PackageDescription
4 | let package = Package()
5 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
6 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Card Tokenisation/Card Details/NoTextEntryUITextFieldHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NoTextEntryUITextFieldHelper.swift
3 | //
4 | //
5 | // Created by Harry Brown on 17/02/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | final class NoTextEntryUITextFieldHelper: NSObject, UITextFieldDelegate {
11 | func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
12 | return false
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Card Tokenisation/CardModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardModel.swift
3 | // CheckoutCocoapodsSample
4 | //
5 | // Created by Daven.Gomes on 01/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | struct CardModel: Equatable, Hashable {
11 | var cardName: String
12 | var cardNumber: String
13 | var expiry: Expiry
14 | var cvv: String
15 |
16 | enum Expiry: Equatable, Hashable {
17 | case string(month: String, year: String)
18 | case int(month: Int, year: Int)
19 |
20 | var month: String {
21 | switch self {
22 | case let .string(month, _):
23 | return month
24 | case let .int(month, _):
25 | return String(month)
26 | }
27 | }
28 |
29 | var year: String {
30 | switch self {
31 | case let .string(_, year):
32 | return year
33 | case let .int(_, year):
34 | return String(year)
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Card Tokenisation/CardTokenisationViewController+ViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardTokenisationViewController+ViewModel.swift
3 | // CheckoutCocoapodsSample
4 | //
5 | // Created by Daven.Gomes on 01/12/2021.
6 | //
7 |
8 | import Foundation
9 | import Checkout
10 |
11 | extension CardTokenizationViewController {
12 | struct ViewModel {
13 | var availableSchemes: Set = Set(Card.Scheme.allCases).symmetricDifference([.unknown])
14 | var cardModel = CardModel(
15 | cardName: "",
16 | cardNumber: "",
17 | expiry: .string(month: "", year: ""),
18 | cvv: "")
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Card Tokenisation/Saved Cards/SavedCardTableViewCell.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SavedCardTableViewCell.swift
3 | // CheckoutCocoapodsSample
4 | //
5 | // Created by Daven.Gomes on 01/12/2021.
6 | //
7 |
8 | import UIKit
9 |
10 | class SavedCardTableViewCell: UITableViewCell {
11 | @IBOutlet weak var cardNameLabel: UILabel!
12 | @IBOutlet weak var cardNumberLabel: UILabel!
13 | @IBOutlet weak var expiryDateLabel: UILabel!
14 | @IBOutlet weak var cvvLabel: UILabel!
15 | }
16 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIApplicationSceneManifest
6 |
7 | UIApplicationSupportsMultipleScenes
8 |
9 | UISceneConfigurations
10 |
11 | UIWindowSceneSessionRoleApplication
12 |
13 |
14 | UISceneConfigurationName
15 | Default Configuration
16 | UISceneDelegateClassName
17 | $(PRODUCT_MODULE_NAME).SceneDelegate
18 | UISceneStoryboardFile
19 | Main
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/SampleAppError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SampleAppError.swift
3 | // CheckoutCocoapodsSample
4 | //
5 | // Created by Daven.Gomes on 07/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | enum SampleAppError: Error {
11 | case cardSchemeNotAccepted
12 | }
13 |
14 | extension SampleAppError: LocalizedError {
15 | public var errorDescription: String? {
16 | switch self {
17 | case .cardSchemeNotAccepted:
18 | return "Card Scheme is not accepted"
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/Timezone+utc.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Timezone+utc.swift
3 | //
4 | //
5 | // Created by Harry Brown on 15/02/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | extension TimeZone {
11 | // swiftlint:disable force_unwrapping
12 | static var utc = TimeZone(identifier: "UTC")!
13 | }
14 |
--------------------------------------------------------------------------------
/Checkout/Samples/Sample/Source/UIColor+CKO.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+CKO.swift
3 | //
4 | //
5 | // Created by Harry Brown on 28/02/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIColor {
11 | static let ckoDarkBlue = UIColor(
12 | red: 12 / 255,
13 | green: 17 / 255,
14 | blue: 66 / 255,
15 | alpha: 1
16 | )
17 |
18 | static let ckoLightBlue = UIColor(
19 | red: 41 / 255,
20 | green: 212 / 255,
21 | blue: 219 / 255,
22 | alpha: 1
23 | )
24 |
25 | static let ckoLightYellow = UIColor(
26 | red: 255 / 255,
27 | green: 255 / 255,
28 | blue: 200 / 255,
29 | alpha: 1
30 | )
31 | }
32 |
--------------------------------------------------------------------------------
/Checkout/Source/3DSHandling/ThreeDSError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSError.swift
3 | // Checkout
4 | //
5 | // Created by Daven.Gomes on 02/02/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | @frozen
11 | /// Defines the 3DS challenge error.
12 | public enum ThreeDSError: CheckoutError {
13 | case couldNotExtractToken
14 | case receivedFailureURL
15 |
16 | public var code: Int {
17 | switch self {
18 | case .couldNotExtractToken:
19 | return 3000
20 | case .receivedFailureURL:
21 | return 3001
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Checkout/Source/3DSHandling/ThreeDSWKNavigationHelperDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSWKNavigationHelperDelegate.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 02/02/2022.
6 | //
7 |
8 | import WebKit
9 |
10 | public protocol ThreeDSWKNavigationHelperDelegate: AnyObject {
11 | func didFinishLoading(navigation: WKNavigation, success: Bool)
12 | func threeDSWKNavigationHelperDelegate(didReceiveResult: Result)
13 | }
14 |
--------------------------------------------------------------------------------
/Checkout/Source/CardUtilities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardUtilities.swift
3 | //
4 | //
5 | // Created by Harry Brown on 29/10/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Provides utility functions for cards.
11 | public enum CardUtilities {}
12 |
--------------------------------------------------------------------------------
/Checkout/Source/CheckoutError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CheckoutError.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 04/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | public protocol CheckoutError: Error, Equatable {
11 | var code: Int { get }
12 | }
13 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/Dictionary+Additions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+Additions.swift
3 | //
4 | //
5 | // Created by Harry Brown on 10/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Dictionary {
11 | /// Returns a new dictionary that has its keys transformed by the supplied closure.
12 | ///
13 | /// - Parameter transform: A closure that transforms the key to a different type.
14 | /// - Returns: A dictionary with transformed keys that correspond to the same values.
15 | func mapKeys(_ transform: (Key) throws -> T) rethrows -> [T: Value] {
16 | return .init(uniqueKeysWithValues: try map { key, value in (try transform(key), value) })
17 | }
18 |
19 | func unpackEnumKeys() -> [T: Value] where Key: RawRepresentable, Key.RawValue == T {
20 | return self.mapKeys(\.rawValue)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/Foundation+Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Foundation+Extensions.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 04/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension Calendar: CalendarProtocol {
11 | func current() -> Date {
12 | Date()
13 | }
14 | }
15 |
16 | extension JSONEncoder: Encoding { }
17 | extension JSONDecoder: Decoding { }
18 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/NSRegularExpression+initStaticPattern.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSRegularExpression+initStaticPattern.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/10/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension NSRegularExpression {
11 | convenience init(staticPattern: StaticString, options: Options = []) {
12 | // swiftlint:disable force_try
13 | try! self.init(pattern: "\(staticPattern)", options: options)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/StringExtensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringExtensions.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 12/08/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | public extension String {
11 |
12 | var decimalDigits: String {
13 | components(separatedBy: .decimalDigits.inverted).joined()
14 | }
15 |
16 | func removeWhitespaces() -> String {
17 | filter { !$0.isWhitespace }
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/TimeZone+constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeZone+constants.swift
3 | // Checkout
4 | //
5 | // Created by Harry Brown on 22/02/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | // swiftlint:disable force_unwrapping
11 | extension TimeZone {
12 | static var utc = TimeZone(identifier: "UTC")!
13 | static var utcMinus12 = TimeZone(identifier: "UTC-12")!
14 | }
15 |
--------------------------------------------------------------------------------
/Checkout/Source/Extension/URL+initStaticString.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+initStaticString.swift
3 | //
4 | //
5 | // Created by Harry Brown on 23/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension URL {
11 | /// Instantiate a `URL` from a `StaticString.`
12 | ///
13 | /// https://www.swiftbysundell.com/articles/constructing-urls-in-swift/#static-urls
14 | /// - Parameter string: The URL string.
15 | /// - Precondition: The URL string must be valid.
16 | init(string: StaticString) {
17 | guard let url = URL(string: "\(string)") else {
18 | preconditionFailure("Invalid static URL string: \(string)")
19 | }
20 |
21 | self = url
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Checkout/Source/Logging/AnyCodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnyCodable.swift
3 | // Checkout
4 | //
5 | // Created by Harry Brown on 10/01/2022.
6 | //
7 |
8 | import Foundation
9 | import CheckoutEventLoggerKit
10 |
11 | protocol AnyCodableProtocol {
12 | func add(customEquality: @escaping (Any, Any) -> Bool, customEncoding: @escaping (Any, inout SingleValueEncodingContainer) throws -> Bool)
13 | }
14 |
15 | final class AnyCodable: AnyCodableProtocol {
16 | func add(customEquality: @escaping (Any, Any) -> Bool, customEncoding: @escaping (Any, inout SingleValueEncodingContainer) throws -> Bool) {
17 | CheckoutEventLoggerKit.AnyCodable.add(customEquality: customEquality, customEncoding: customEncoding)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Checkout/Source/Logging/CheckoutLogEvent+Types.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CheckoutLogEvent+Types.swift
3 | //
4 | //
5 | // Created by Harry Brown on 05/01/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | extension CheckoutLogEvent {
11 | struct TokenRequestData: Equatable {
12 | let tokenType: TokenRequest.TokenType?
13 | let publicKey: String
14 | }
15 |
16 | struct SecurityCodeTokenRequestData: Equatable {
17 | let tokenType: SecurityCodeTokenType?
18 | let publicKey: String
19 | }
20 |
21 | struct TokenResponseData: Equatable {
22 | let tokenID: String?
23 | let scheme: String?
24 | let httpStatusCode: Int?
25 | let serverError: TokenisationError.ServerError?
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Checkout/Source/Logging/DateProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateProvider.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | class DateProvider: DateProviding {
11 | func current() -> Date {
12 | return Date()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/Address.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Address.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 09/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Initializes a Address object.
11 | public struct Address: Equatable {
12 | public let addressLine1: String?
13 | public let addressLine2: String?
14 | public let city: String?
15 | public let state: String?
16 | public let zip: String?
17 | public let country: Country?
18 |
19 | public init(addressLine1: String?, addressLine2: String?, city: String?, state: String?, zip: String?, country: Country?) {
20 | self.addressLine1 = addressLine1
21 | self.addressLine2 = addressLine2
22 | self.city = city
23 | self.state = state
24 | self.zip = zip
25 | self.country = country
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/Card.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Card.swift
3 | // Checkout
4 | //
5 | // Created by Harry Brown on 01/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct Card: Equatable {
11 | public let number: String
12 | public let expiryDate: ExpiryDate
13 | public let name: String?
14 | public let cvv: String?
15 | public let billingAddress: Address?
16 | public let phone: Phone?
17 |
18 | public init(number: String, expiryDate: ExpiryDate, name: String?, cvv: String?, billingAddress: Address?, phone: Phone?) {
19 | self.number = number
20 | self.expiryDate = expiryDate
21 | self.name = name
22 | self.cvv = cvv
23 | self.billingAddress = billingAddress
24 | self.phone = phone
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/Environment.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Environment.swift
3 | //
4 | //
5 | // Created by Harry Brown on 23/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol BaseURLProviding {
11 | var baseURL: URL { get }
12 | }
13 |
14 | /// Environment Enum for Production and Sandbox end points.
15 | public enum Environment: String, BaseURLProviding {
16 | case production
17 | case sandbox
18 |
19 | var baseURL: URL {
20 | switch self {
21 | case .production:
22 | return URL(string: "https://api.checkout.com/")
23 | case .sandbox:
24 | return URL(string: "https://api.sandbox.checkout.com/")
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/ExpiryDate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExpiryDate.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 03/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// ExpiryDate struct representing month and year as Int for the expiry date field.
11 | public struct ExpiryDate: Equatable {
12 | public let month: Int
13 | public let year: Int
14 |
15 | public init(month: Int, year: Int) {
16 | self.month = month
17 | self.year = year
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/PaymentSource.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaymentSource.swift
3 | //
4 | //
5 | // Created by Harry Brown on 23/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Defines the payment source - either card or Apple Pay.
11 | public enum PaymentSource: Equatable {
12 | case card(Card)
13 | case applePay(ApplePay)
14 | }
15 |
--------------------------------------------------------------------------------
/Checkout/Source/Model/Phone.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Phone.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 09/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Initializes a Phone object with number and country.
11 | public struct Phone: Equatable {
12 | public let number: String?
13 | public let country: Country?
14 |
15 | public init(number: String?, country: Country?) {
16 | self.number = number
17 | self.country = country
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Checkout/Source/Models/ApplePay.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ApplePay.swift
3 | //
4 | //
5 | // Created by Harry Brown on 07/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Apple Pay field types.
11 | public struct ApplePay: Equatable {
12 | public let tokenData: Data
13 | public init(tokenData: Data) {
14 | self.tokenData = tokenData
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Checkout/Source/Network/Models/NetworkRequestResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NetworkRequestResult.swift
3 | //
4 | //
5 | // Created by Harry Brown on 24/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | enum NetworkRequestResult {
11 | case response(Response)
12 | case errorResponse(ErrorResponse)
13 | case networkError(NetworkError)
14 | }
15 |
16 | extension NetworkRequestResult: Equatable where Response: Equatable, ErrorResponse: Equatable {}
17 |
--------------------------------------------------------------------------------
/Checkout/Source/Network/Models/SecurityCode/SecurityCodeError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecurityCodeError.swift
3 | //
4 | //
5 | // Created by Okhan Okbay on 05/10/2023.
6 | //
7 |
8 | import Foundation
9 |
10 | extension TokenisationError {
11 | public enum SecurityCodeError: CheckoutError {
12 | case missingAPIKey
13 | case couldNotBuildURLForRequest
14 | case networkError(NetworkError)
15 | case serverError(TokenisationError.ServerError)
16 | case invalidSecurityCode
17 |
18 | public var code: Int {
19 | switch self {
20 | case .missingAPIKey:
21 | return 4001
22 | case .couldNotBuildURLForRequest:
23 | return 3007
24 | case .networkError(let networkError):
25 | return networkError.code
26 | case .serverError(let serverError):
27 | return serverError.code
28 | case .invalidSecurityCode:
29 | return 3006
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Checkout/Source/Network/Models/SecurityCode/SecurityCodeRequest.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecurityCodeRequest.swift
3 | //
4 | //
5 | // Created by Okhan Okbay on 05/10/2023.
6 | //
7 |
8 | import Foundation
9 |
10 | struct SecurityCodeRequest: Encodable, Equatable {
11 | let type: String = "cvv"
12 | let tokenData: TokenData
13 | }
14 |
15 | struct TokenData: Encodable, Equatable {
16 | let securityCode: String
17 |
18 | enum CodingKeys: String, CodingKey {
19 | case securityCode = "cvv"
20 | }
21 | }
22 |
23 | // For logging purposes only
24 | enum SecurityCodeTokenType: String, Codable, Equatable {
25 | case cvv
26 | }
27 |
--------------------------------------------------------------------------------
/Checkout/Source/Network/Models/SecurityCode/SecurityCodeResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecurityCodeResponse.swift
3 | //
4 | //
5 | // Created by Okhan Okbay on 05/10/2023.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct SecurityCodeResponse: Decodable, Equatable {
11 | /// Type of the tokenisation. In SecurityCodeResponse, it's always `cvv`
12 | public let type: String
13 |
14 | /// Reference token
15 | public let token: String
16 |
17 | /// Date/time of the token expiration. The format is `2023-11-01T13:36:16.2003858Z`
18 | public let expiresOn: String
19 | }
20 |
--------------------------------------------------------------------------------
/Checkout/Source/Network/Models/TokenResponse.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TokenResponse.swift
3 | //
4 | //
5 | // Created by Harry Brown on 24/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | struct TokenResponse: Decodable, Equatable {
11 | let type: TokenRequest.TokenType
12 | let token: String
13 | let expiresOn: String
14 | let expiryMonth: Int
15 | let expiryYear: Int
16 | let scheme: String?
17 | let schemeLocal: String?
18 | let last4: String
19 | let bin: String
20 | let cardType: String?
21 | let cardCategory: String?
22 | let issuer: String?
23 | let issuerCountry: String?
24 | let productId: String?
25 | let productType: String?
26 | let billingAddress: TokenRequest.Address?
27 | let phone: TokenRequest.Phone?
28 | let name: String?
29 | }
30 |
--------------------------------------------------------------------------------
/Checkout/Source/Protocols/CalendarProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CalendarProtocol.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 04/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol CalendarProtocol: DateProviding {
11 | func date(from components: DateComponents) -> Date?
12 | func date(byAdding component: Calendar.Component, value: Int, to date: Date, wrappingComponents: Bool) -> Date?
13 | func component(_ component: Calendar.Component, from date: Date) -> Int
14 | }
15 |
16 | extension CalendarProtocol {
17 | func date(byAdding component: Calendar.Component, value: Int, to date: Date) -> Date? {
18 | return self.date(byAdding: component, value: value, to: date, wrappingComponents: false)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Checkout/Source/Protocols/DateProviding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateProviding.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol DateProviding {
11 | func current() -> Date
12 | }
13 |
--------------------------------------------------------------------------------
/Checkout/Source/Protocols/Decoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Decoding.swift
3 | //
4 | //
5 | // Created by Harry Brown on 25/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol Decoding {
11 | func decode(_ type: T.Type, from data: Data) throws -> T where T: Decodable
12 | }
13 |
--------------------------------------------------------------------------------
/Checkout/Source/Protocols/DeviceInformationProviding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeviceInformationProviding.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/12/2021.
6 | //
7 |
8 | protocol DeviceInformationProviding {
9 | var modelName: String { get }
10 | var systemVersion: String { get }
11 | }
12 |
--------------------------------------------------------------------------------
/Checkout/Source/Protocols/Encoding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Encoding.swift
3 | //
4 | //
5 | // Created by Harry Brown on 25/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol Encoding {
11 | func encode(_ value: T) throws -> Data where T: Encodable
12 | }
13 |
--------------------------------------------------------------------------------
/Checkout/Source/Tokenisation/Error/TokenisationError+ServerError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TokenisationError+ServerError.swift
3 | //
4 | //
5 | // Created by Harry Brown on 24/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension TokenisationError {
11 | /// ServerError object as CheckoutError when creating card token
12 | public struct ServerError: CheckoutError, Codable, Equatable {
13 | public let requestID: String
14 | public let errorType: String
15 | public let errorCodes: [String]
16 |
17 | private enum CodingKeys: String, CodingKey {
18 | case requestID = "requestId"
19 | case errorType
20 | case errorCodes
21 | }
22 |
23 | public let code = 3000
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Checkout/Source/Tokenisation/Error/TokenisationError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TokenisationError.swift
3 | //
4 | //
5 | // Created by Harry Brown on 23/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Defines an error that occurs during card tokenisation.
11 | public enum TokenisationError {}
12 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 18/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | public enum Constants {
11 | enum Address {
12 | static let addressLine1Length = 200
13 | static let addressLine2Length = 200
14 | static let cityLength = 50
15 | static let stateLength = 50
16 | static let zipLength = 50
17 | static let countryLength = 2
18 | }
19 |
20 | public enum Phone {
21 | public static let phoneMaxLength = 25
22 | static let phoneMinLength = 6
23 | static let countryCodeMinLength = 1
24 | static let countryCodeMaxLength = 7
25 | }
26 |
27 | enum Product {
28 | static let version = "4.3.8"
29 | static let name = "checkout-ios-sdk"
30 | static let userAgent = "checkout-sdk-ios/\(version)"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError+Address.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationError+Address.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 18/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension ValidationError {
11 | public enum Address: CheckoutError, CaseIterable {
12 | case addressLine1IncorrectLength
13 | case addressLine2IncorrectLength
14 | case invalidCityLength
15 | case invalidCountry
16 | case invalidStateLength
17 | case invalidZipLength
18 |
19 | public var code: Int {
20 | switch self {
21 | case .addressLine1IncorrectLength:
22 | return 1012
23 | case .addressLine2IncorrectLength:
24 | return 1013
25 | case .invalidCityLength:
26 | return 1014
27 | case .invalidCountry:
28 | return 1015
29 | case .invalidStateLength:
30 | return 1016
31 | case .invalidZipLength:
32 | return 1017
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError+CVV.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationError+CVV.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 09/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension ValidationError {
11 | public enum CVV: CheckoutError, CaseIterable {
12 | case containsNonDigits
13 | case invalidLength
14 |
15 | public var code: Int {
16 | switch self {
17 | case .containsNonDigits:
18 | return 1002
19 | case .invalidLength:
20 | return 1003
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError+CardNumber.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardNumberValidationError.swift
3 | //
4 | //
5 | // Created by Harry Brown on 29/10/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | extension ValidationError {
11 | public enum CardNumber: CheckoutError, CaseIterable {
12 | case invalidCharacters
13 |
14 | public var code: Int {
15 | switch self {
16 | case .invalidCharacters:
17 | return 1001
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError+EagerCardNumber.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationError+EagerCardNumber.swift
3 | // Checkout
4 | //
5 | // Created by Harry Brown on 23/05/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | extension ValidationError {
11 | public enum EagerCardNumber: CheckoutError {
12 | case cardNumber(ValidationError.CardNumber)
13 | case invalidScheme
14 | case tooLong
15 |
16 | public var code: Int {
17 | switch self {
18 | case .cardNumber(let error):
19 | return error.code
20 | case .tooLong:
21 | return 1020
22 | case .invalidScheme:
23 | return 1021
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError+Phone.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationError+Phone.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 18/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | public extension ValidationError {
11 | /// Enums representing the ValidationError for Phone field.
12 | enum Phone: CheckoutError, CaseIterable {
13 | case numberIncorrectLength
14 | case countryCodeIncorrectLength
15 |
16 | public var code: Int {
17 | switch self {
18 | case .numberIncorrectLength:
19 | return 1018
20 | case .countryCodeIncorrectLength:
21 | return 1019
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/Error/ValidationError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationError.swift
3 | // Checkout
4 | //
5 | // Created by Harry Brown on 01/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Defines the validation error enum on each of the possible input fields.
11 | public enum ValidationError {}
12 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/LuhnChecker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LuhnChecker.swift
3 | //
4 | //
5 | // Created by Harry Brown on 29/10/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol LuhnChecking {
11 | func luhnCheck(cardNumber: String) -> Bool
12 | }
13 |
14 | class LuhnChecker: LuhnChecking {
15 | func luhnCheck(cardNumber: String) -> Bool {
16 | var sum = 0
17 | let digitStrings = cardNumber.reversed().map(String.init)
18 |
19 | for tuple in digitStrings.enumerated() {
20 | guard let digit = Int(tuple.element) else {
21 | return false
22 | }
23 |
24 | let odd = tuple.offset % 2 == 1
25 |
26 | switch (odd, digit) {
27 | case (true, 9):
28 | sum += 9
29 | case (true, 0...8):
30 | sum += (digit * 2) % 9
31 | default:
32 | sum += digit
33 | }
34 | }
35 | return sum % 10 == 0
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Checkout/Source/Validation/ValidationResult.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ValidationResult.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 04/11/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Defines the outcome of a validation check, either success or failure.
11 | public enum ValidationResult: Equatable {
12 | case success
13 | case failure(T)
14 | }
15 |
--------------------------------------------------------------------------------
/CheckoutTests/3DSHandling/ThreeDSErrorTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSErrorTests.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/02/2022.
6 | //
7 |
8 | import XCTest
9 | import Checkout
10 |
11 | final class ThreeDSErrorTests: XCTestCase {
12 | func test_code_couldNotExtractToken() {
13 | let subject = ThreeDSError.couldNotExtractToken
14 |
15 | XCTAssertEqual(subject.code, 3000)
16 | }
17 |
18 | func test_code_receivedFailureURL() {
19 | let subject = ThreeDSError.receivedFailureURL
20 |
21 | XCTAssertEqual(subject.code, 3001)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CheckoutTests/Extension/Dictionary+AdditionsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary+AdditionsTests.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/12/2021.
6 | //
7 |
8 | import XCTest
9 | @testable import Checkout
10 |
11 | class DictionaryAdditionsTests: XCTestCase {
12 | func test_mapKeys() {
13 | let subject = [1: "test", 2: "value", 3: "world"]
14 | let expected = [5: "test", 10: "value", 15: "world"]
15 | XCTAssertEqual(subject.mapKeys { $0 * 5 }, expected)
16 | }
17 |
18 | func test_unpackEnumKeys() {
19 | let subject: [TestKey: String] = [.abc: "test", .def: "value", .ghi: "world"]
20 | let expected = [1: "test", 13: "value", 72: "world"]
21 |
22 | XCTAssertEqual(subject.unpackEnumKeys(), expected)
23 | }
24 |
25 | private enum TestKey: Int {
26 | case abc = 1
27 | case def = 13
28 | case ghi = 72
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CheckoutTests/Extension/TimeZone+constantsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TimeZone+constantsTests.swift
3 | // CheckoutTests
4 | //
5 | // Created by Harry Brown on 22/02/2022.
6 | //
7 |
8 | import XCTest
9 | @testable import Checkout
10 |
11 | final class TimezoneConstantsTests: XCTestCase {
12 | func test_utc() {
13 | let subject = TimeZone.utc
14 |
15 | XCTAssertNotNil(subject.description)
16 | }
17 |
18 | func test_utcMinus12() {
19 | let subject = TimeZone.utcMinus12
20 |
21 | XCTAssertNotNil(subject.description)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CheckoutTests/Logging/DateProviderTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DateProviderTests.swift
3 | //
4 | //
5 | // Created by Harry Brown on 22/12/2021.
6 | //
7 |
8 | import XCTest
9 | @testable import Checkout
10 |
11 | class DateProviderTests: XCTestCase {
12 | let subject = DateProvider()
13 |
14 | func test_current() {
15 | let expected = Date()
16 | let actual = subject.current()
17 |
18 | let difference = actual.timeIntervalSinceReferenceDate - expected.timeIntervalSinceReferenceDate
19 |
20 | XCTAssertTrue(difference <= 5)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CheckoutTests/Model/EnvironmentTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // EnvironmentTests.swift
3 | //
4 | //
5 | // Created by Harry Brown on 08/12/2021.
6 | //
7 |
8 | import XCTest
9 | @testable import Checkout
10 |
11 | final class EnvironmentTests: XCTestCase {
12 | func test_baseURL_production() {
13 | let subject = Environment.production
14 |
15 | XCTAssertEqual(subject.baseURL, URL(string: "https://api.checkout.com/"))
16 | }
17 |
18 | func test_baseURL_sandbox() {
19 | let subject = Environment.sandbox
20 |
21 | XCTAssertEqual(subject.baseURL, URL(string: "https://api.sandbox.checkout.com/"))
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubAddressValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubAddressValidator.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 18/11/2021.
6 | //
7 |
8 | @testable import Checkout
9 |
10 | final class StubAddressValidator: AddressValidating {
11 | var validateToReturn: ValidationResult = .success
12 | private(set) var validateCalledWith: Address?
13 |
14 | func validate(_ address: Address) -> ValidationResult {
15 | validateCalledWith = address
16 | return validateToReturn
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubAnyCodable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubAnyCodable.swift
3 | //
4 | //
5 | // Created by Harry Brown on 10/01/2022.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubAnyCodable: AnyCodableProtocol {
12 | private(set) var addCalledWith: (
13 | customEquality: (Any, Any) -> Bool,
14 | customEncoding: (Any, inout SingleValueEncodingContainer) throws -> Bool
15 | )?
16 |
17 | func add(customEquality: @escaping (Any, Any) -> Bool, customEncoding: @escaping (Any, inout SingleValueEncodingContainer) throws -> Bool) {
18 | addCalledWith = (customEquality, customEncoding)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubBaseURLProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubBaseURLProvider.swift
3 | //
4 | //
5 | // Created by Harry Brown on 01/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | // swiftlint:disable force_unwrapping
12 | final class StubBaseURLProvider: BaseURLProviding {
13 | var baseURLToReturn = URL(string: "https://www.checkout.com/")!
14 | private(set) var baseURLCalled = false
15 |
16 | var baseURL: URL {
17 | baseURLCalled = true
18 | return baseURLToReturn
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubDateProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubDateProvider.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | class StubDateProvider: DateProviding {
12 | private(set) var currentCalled = false
13 | var currentToReturn = Date(timeIntervalSince1970: 0)
14 |
15 | func current() -> Date {
16 | currentCalled = true
17 | return currentToReturn
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubDecoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubDecoder.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubDecoder: Decoding {
12 | var decodeToReturn: Decodable?
13 | private(set) var decodeCalledWith: (type: Decodable.Type, data: Data)?
14 |
15 | func decode(_ type: T.Type, from data: Data) throws -> T where T: Decodable {
16 | decodeCalledWith = (type, data)
17 |
18 | guard let decodeToReturn = decodeToReturn as? T else {
19 | throw StubDecodingError.wrongReturnType
20 | }
21 |
22 | return decodeToReturn
23 | }
24 |
25 | enum StubDecodingError: Error {
26 | case wrongReturnType
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubDeviceInformationProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubDeviceInformationProvider.swift
3 | //
4 | //
5 | // Created by Harry Brown on 22/12/2021.
6 | //
7 |
8 | @testable import Checkout
9 |
10 | final class StubDeviceInformationProvider: DeviceInformationProviding {
11 | private(set) var modelNameCalled = false
12 | var modelNameToReturn: String = "iPhone11,4"
13 |
14 | var modelName: String {
15 | modelNameCalled = true
16 | return modelNameToReturn
17 | }
18 |
19 | private(set) var systemVersionCalled = false
20 | var systemVersionToReturn: String = "13.2.1"
21 |
22 | var systemVersion: String {
23 | systemVersionCalled = true
24 | return systemVersionToReturn
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubEncoder.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubEncoder.swift
3 | //
4 | //
5 | // Created by Harry Brown on 01/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubEncoder: Encoding {
12 | var encodeToReturn = Data()
13 | private(set) var encodeCalledWith: Encodable?
14 |
15 | func encode(_ value: T) throws -> Data where T: Encodable {
16 | encodeCalledWith = value
17 | return encodeToReturn
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubError.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubError.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | enum StubError: LocalizedError {
11 | case one
12 |
13 | var errorDescription: String? {
14 | switch self {
15 | case .one:
16 | return "StubError.one"
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubLuhnChecker.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubLuhnChecker.swift
3 | //
4 | //
5 | // Created by Harry Brown on 29/10/2021.
6 | //
7 |
8 | @testable import Checkout
9 |
10 | final class StubLuhnChecker: LuhnChecking {
11 | private(set) var luhnCheckCalledWith: String?
12 | var luhnCheckToReturn = true
13 |
14 | func luhnCheck(cardNumber: String) -> Bool {
15 | luhnCheckCalledWith = cardNumber
16 | return luhnCheckToReturn
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubPhoneValidator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubPhoneValidator.swift
3 | //
4 | //
5 | // Created by Daven.Gomes on 18/11/2021.
6 | //
7 |
8 | @testable import Checkout
9 |
10 | final class StubPhoneValidator: PhoneValidating {
11 | var validateToReturn: ValidationResult = .success
12 | private(set) var validateCalledWith: Phone?
13 |
14 | func validate(_ phone: Phone) -> ValidationResult {
15 | validateCalledWith = phone
16 | return validateToReturn
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubRequestFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubRequestFactory.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubRequestFactory: RequestProviding {
12 | var createToReturn: Result<
13 | NetworkManager.RequestParameters,
14 | RequestFactory.RequestError
15 | > = .failure(.baseURLCouldNotBeConvertedToComponents)
16 | private(set) var createCalledWith: RequestFactory.Request?
17 |
18 | func create(request: RequestFactory.Request) -> Result {
19 | createCalledWith = request
20 |
21 | return createToReturn
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubThreeDSWKNavigationHelperDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubThreeDSWKNavigationHelperDelegate.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/02/2022.
6 | //
7 |
8 | import Checkout
9 | import WebKit
10 |
11 | final class StubThreeDSWKNavigationHelperDelegate: ThreeDSWKNavigationHelperDelegate {
12 | private(set) var didReceiveResultCalledWith: [Result] = []
13 | private(set) var didFinishLoadingCalledWith: (navigation: WKNavigation, success: Bool)?
14 |
15 | func threeDSWKNavigationHelperDelegate(didReceiveResult: Result) {
16 | didReceiveResultCalledWith.append(didReceiveResult)
17 | }
18 |
19 | func didFinishLoading(navigation: WKNavigation, success: Bool) {
20 | didFinishLoadingCalledWith = (navigation, success)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubTokenDetailsFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubTokenDetailsFactory.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | // swiftlint:disable implicitly_unwrapped_optional
12 | final class StubTokenDetailsFactory: TokenDetailsProviding {
13 | var createToReturn: TokenDetails!
14 | private(set) var createCalledWith: TokenResponse?
15 |
16 | func create(tokenResponse: TokenResponse) -> TokenDetails {
17 | createCalledWith = tokenResponse
18 |
19 | return createToReturn
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubTokenRequestFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubTokenRequestFactory.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubTokenRequestFactory: TokenRequestProviding {
12 | var createToReturn: Result<
13 | TokenRequest,
14 | TokenisationError.TokenRequest
15 | > = .failure(.cardValidationError(.cvv(.invalidLength)))
16 | private(set) var createCalledWith: PaymentSource?
17 |
18 | func create(paymentSource: PaymentSource) -> Result {
19 | createCalledWith = paymentSource
20 |
21 | return createToReturn
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubURLHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubURLHelper.swift
3 | // CheckoutTests
4 | //
5 | // Created by Harry Brown on 21/02/2022.
6 | //
7 |
8 | import Foundation
9 | @testable import Checkout
10 |
11 | final class StubURLHelper: URLHelping {
12 | private(set) var urlsMatchCalledWith: [(redirectUrl: URL, matchingUrl: URL)] = []
13 | var urlsMatchToReturn: [URL: [URL: Bool]] = [:]
14 |
15 | func urlsMatch(redirectUrl: URL, matchingUrl: URL) -> Bool {
16 | urlsMatchCalledWith.append((redirectUrl, matchingUrl))
17 | return urlsMatchToReturn[redirectUrl]?[matchingUrl] ?? false
18 | }
19 |
20 | private(set) var extractTokenCalledWith: [URL] = []
21 | var extractTokenToReturn: String?
22 |
23 | func extractToken(from url: URL) -> String? {
24 | extractTokenCalledWith.append(url)
25 | return extractTokenToReturn
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubURLSession.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubURLSession.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | final class StubURLSession: URLSession {
11 | private(set) var dataTaskCalledWithRequest: URLRequest?
12 | private(set) var dataTaskCalledWithCompletionHandler: ((Data?, URLResponse?, Error?) -> Void)?
13 | var dataTaskReturnValue: URLSessionDataTask = StubURLSessionDataTask()
14 |
15 | override func dataTask(
16 | with request: URLRequest,
17 | completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void
18 | ) -> URLSessionDataTask {
19 | dataTaskCalledWithRequest = request
20 | dataTaskCalledWithCompletionHandler = completionHandler
21 |
22 | return dataTaskReturnValue
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubURLSessionDataTask.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubURLSessionDataTask.swift
3 | //
4 | //
5 | // Created by Harry Brown on 02/12/2021.
6 | //
7 |
8 | import Foundation
9 |
10 | final class StubURLSessionDataTask: URLSessionDataTask {
11 | private(set) var resumeCalled = false
12 |
13 | override func resume() {
14 | resumeCalled = true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CheckoutTests/Stubs/StubWKNavigationAction.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StubWKNavigationAction.swift
3 | //
4 | //
5 | // Created by Harry Brown on 21/02/2022.
6 | //
7 |
8 | import WebKit
9 |
10 | final class StubWKNavigationAction: WKNavigationAction {
11 | // swiftlint:disable:next force_unwrapping
12 | var requestToReturn = URLRequest(url: URL(string: "https://www.example.com")!)
13 | override var request: URLRequest { requestToReturn }
14 | }
15 |
--------------------------------------------------------------------------------
/Source/CardUtils.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Checkout
3 |
4 | /// Payment Form Utilities
5 | enum CardUtils {
6 |
7 | // MARK: - Methods
8 |
9 | /// Format the card number based on the card type
10 | /// e.g. Visa card: 4242 4242 4242 4242
11 | ///
12 | /// - parameter cardNumber: Card number
13 | /// - parameter cardType: Card type
14 | ///
15 | ///
16 | /// - returns: The formatted card number
17 | static func format(cardNumber: String, scheme: Card.Scheme) -> String {
18 | var cardNumber = cardNumber
19 |
20 | for gap in scheme.cardGaps.sorted(by: >) where gap < cardNumber.count {
21 | cardNumber.insert(" ", at: cardNumber.index(cardNumber.startIndex, offsetBy: gap))
22 | }
23 |
24 | return cardNumber
25 | }
26 |
27 | static func removeNonDigits(from string: String) -> String {
28 | return string.replacingOccurrences(of: "[^0-9]", with: "", options: .regularExpression)
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Source/CheckoutColor.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIColor {
4 | convenience init(hex: String, alpha: CGFloat = 1.0) {
5 | var cString = hex
6 | .filter { !$0.isWhitespace }
7 | .uppercased()
8 |
9 | if cString.hasPrefix("#") { cString.removeFirst() }
10 |
11 | guard cString.count == 6 else {
12 | self.init(hex: "ff0000") // gray color
13 | return
14 | }
15 |
16 | var rgbValue: UInt64 = 0
17 | Scanner(string: cString).scanHexInt64(&rgbValue)
18 |
19 | self.init(
20 | red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
21 | green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
22 | blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
23 | alpha: CGFloat(1.0)
24 | )
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Source/Core/Constants/Constants+Padding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants+Padding.swift
3 | // Frames
4 | //
5 | // Copyright © 2022 Checkout. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | // swiftlint:disable identifier_name
11 | extension Constants {
12 | static let defaultNavigationHeaderFontSize: Double = 15
13 |
14 | public enum Padding: Double {
15 |
16 | /// parameter size: 2
17 | case xxs = 2
18 |
19 | /// parameter size: 8
20 | case xs = 8
21 |
22 | /// parameter size: 10
23 | case s = 10
24 |
25 | /// parameter size: 16
26 | case m = 16
27 |
28 | /// parameter size: 20
29 | case l = 20
30 |
31 | /// parameter size: 24
32 | case xl = 24
33 |
34 | /// parameter size: 28
35 | case xxl = 28
36 |
37 | /// parameter size: 40
38 | case xxxl = 40
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Source/Core/Constants/Constants.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constants.swift
3 | // Frames
4 | //
5 | // Copyright © 2022 Checkout. All rights reserved.
6 | //
7 |
8 | enum Constants {
9 |
10 | static let productName = "frames-ios-sdk"
11 | static let version = "4.3.8"
12 | static let userAgent = "checkout-sdk-frames-ios/\(version)"
13 |
14 | enum Logging {
15 | enum BarStyle: String {
16 | case `default`
17 | case black
18 | case blackTranslucent
19 | case unknown
20 | }
21 | }
22 |
23 | enum Bundle: String {
24 | case version = "CFBundleShortVersionString"
25 |
26 | enum FallbackValues: String {
27 | case noBundleIdentifier = "unavailableAppPackageName"
28 | case noVersion = "unavailableAppPackageVersion"
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/Core/ContentTypeProviding.swift:
--------------------------------------------------------------------------------
1 | protocol ContentTypeProviding {
2 |
3 | var contentType: String { get }
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/Source/Core/Dispatching.swift:
--------------------------------------------------------------------------------
1 | protocol Dispatching {
2 |
3 | func async(_ block: @escaping () -> Void)
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/Source/Core/Environment.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Checkout
3 | import CheckoutEventLoggerKit
4 |
5 | /// Checkout API Environment
6 | ///
7 | /// - live
8 | /// - sandbox
9 | @frozen public enum Environment: String {
10 |
11 | /// live environment used for production using
12 | case live
13 |
14 | /// sandbox environment used for development
15 | case sandbox
16 |
17 | var checkoutEnvironment: Checkout.Environment {
18 | switch self {
19 | case .live:
20 | return .production
21 | case .sandbox:
22 | return .sandbox
23 | }
24 | }
25 |
26 | var eventLoggerEnvironment: CheckoutEventLoggerKit.Environment {
27 | switch self {
28 | case .live:
29 | return .production
30 | case .sandbox:
31 | return .sandbox
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Source/Core/Logging/CorrelationIDGenerator.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol CorrelationIDManaging {
4 |
5 | func generateCorrelationID() -> String
6 | func destroyCorrelationID()
7 | }
8 |
9 | final class CorrelationIDManager: CorrelationIDManaging {
10 |
11 | private var correlationID: String?
12 |
13 | // MARK: - CorrelationIDManaging
14 |
15 | func generateCorrelationID() -> String {
16 | guard let correlationIDValue = correlationID else {
17 | let newCorrelationId = UUID.init().uuidString.lowercased()
18 | self.correlationID = newCorrelationId
19 | return newCorrelationId
20 | }
21 | return correlationIDValue
22 | }
23 |
24 | func destroyCorrelationID() {
25 | correlationID = nil
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/Source/Core/Logging/DateProvider.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol DateProviding {
4 |
5 | /// Returns a `Date` a date value initialized to the current date and time.
6 | var currentDate: Date { get }
7 |
8 | }
9 |
10 | final class DateProvider: DateProviding {
11 |
12 | var currentDate: Date { return Date() }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Source/Core/Logging/PropertyProviding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PropertyProviding.swift
3 | // Frames
4 | //
5 | // Created by Harry Brown on 23/03/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import CheckoutEventLoggerKit
10 |
11 | protocol PropertyProviding {
12 | var properties: [FramesLogEvent.Property: AnyCodable] { get }
13 | }
14 |
15 | extension PropertyProviding {
16 | var rawProperties: [String: AnyCodable] {
17 | return properties.mapKeys(\.rawValue)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Source/Core/Models/SecurityCodeTokenDetails.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SecurityCodeTokenDetails.swift
3 | //
4 | //
5 | // Created by Okhan Okbay on 10/10/2023.
6 | //
7 |
8 | import Checkout
9 | import Foundation
10 |
11 | public struct SecurityCodeTokenDetails {
12 | public let type: String
13 | public let token: String
14 | public let expiresOn: String
15 |
16 | init(type: String, token: String, expiresOn: String) {
17 | self.type = type
18 | self.token = token
19 | self.expiresOn = expiresOn
20 | }
21 |
22 | init(response: SecurityCodeResponse) {
23 | self.type = response.type
24 | self.token = response.token
25 | self.expiresOn = response.expiresOn
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Source/Core/Models/Typealiases.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Typealiases.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 11/08/2022.
6 | //
7 |
8 | import Checkout
9 |
10 | public typealias Card = Checkout.Card
11 | public typealias Address = Checkout.Address
12 | public typealias Phone = Checkout.Phone
13 | public typealias Country = Checkout.Country
14 | public typealias TokenDetails = Checkout.TokenDetails
15 | public typealias TokenRequestError = Checkout.TokenisationError.TokenRequest
16 | public typealias ApplePay = Checkout.ApplePay
17 | public typealias PhoneValidator = Checkout.PhoneValidator
18 | public typealias SecurityCodeError = Checkout.TokenisationError.SecurityCodeError
19 |
--------------------------------------------------------------------------------
/Source/Core/ThreeDSWKNavigationHelperFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ThreeDSWKNavigationHelperFactory.swift
3 | // Frames
4 | //
5 | // Created by Harry Brown on 21/06/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import Checkout
11 |
12 | protocol ThreeDSWKNavigationHelperFactoryProtocol {
13 | func build(successURL: URL?, failureURL: URL?) -> ThreeDSWKNavigationHelping
14 | }
15 |
16 | final class ThreeDSWKNavigationHelperFactory: ThreeDSWKNavigationHelperFactoryProtocol {
17 |
18 | func build(successURL: URL?, failureURL: URL?) -> ThreeDSWKNavigationHelping {
19 | return ThreeDSWKNavigationHelper(successURL: successURL, failureURL: failureURL)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Source/Core/TopLevelDecoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol TopLevelDecoder {
4 |
5 | func decode(_ type: T.Type, from: Data) throws -> T
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/Source/Core/TopLevelEncoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol TopLevelEncoder {
4 |
5 | func encode(_ value: T) throws -> Data
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/Source/Extensions/DispatchQueue+Dispatching.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension DispatchQueue: Dispatching {
4 |
5 | func async(_ block: @escaping () -> Void) {
6 | async(group: nil, execute: block)
7 | }
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/Source/Extensions/JSONDecoder+TopLevelDecoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension JSONDecoder: TopLevelDecoder { }
4 |
--------------------------------------------------------------------------------
/Source/Extensions/JSONEncoder+ContentTypeProviding.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension JSONEncoder: ContentTypeProviding {
4 |
5 | var contentType: String { return "application/json" }
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/Source/Extensions/JSONEncoder+TopLevelEncoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension JSONEncoder: TopLevelEncoder { }
4 |
--------------------------------------------------------------------------------
/Source/Extensions/UIBarStyle+stringValue.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarStyle+stringValue.swift
3 | // Frames
4 | //
5 | // Created by Harry Brown on 24/03/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | extension UIBarStyle {
12 | var stringValue: String {
13 | return barStyle.rawValue
14 | }
15 |
16 | private var barStyle: Constants.Logging.BarStyle {
17 | switch self {
18 | case .default:
19 | return .default
20 | case .black, .blackOpaque:
21 | return .black
22 | case .blackTranslucent:
23 | return .blackTranslucent
24 | @unknown default:
25 | return .unknown
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Source/Extensions/UIBezierPathExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIBezierPathExntension.swift
3 | //
4 | //
5 | // Created by Ehab Alsharkawy on 14/11/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIBezierPath {
11 |
12 | func drawLine(startX: CGFloat, startY: CGFloat, endX: CGFloat, endY: CGFloat) {
13 | let startPoint = CGPoint(x: startX, y: startY)
14 | let endPoint = CGPoint(x: endX, y: endY)
15 | move(to: startPoint)
16 | addLine(to: endPoint)
17 | }
18 |
19 | func drawCorner(startX: CGFloat, startY: CGFloat, endX: CGFloat, endY: CGFloat, controlX: CGFloat, controlY: CGFloat) {
20 | let startPoint = CGPoint(x: startX, y: startY)
21 | let endPoint = CGPoint(x: endX, y: endY)
22 | let controlPoint = CGPoint(x: controlX, y: controlY)
23 | move(to: startPoint)
24 | addQuadCurve(to: endPoint, controlPoint: controlPoint)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Source/Extensions/UIFont+PropertyProviding.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+PropertyProviding.swift
3 | // Frames
4 | //
5 | // Created by Harry Brown on 23/03/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import CheckoutEventLoggerKit
11 |
12 | extension UIFont: PropertyProviding {
13 | var properties: [FramesLogEvent.Property: AnyCodable] {
14 | return [
15 | .size: Double(pointSize),
16 | .name: fontName
17 | ].mapValues(AnyCodable.init(_:))
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Source/Extensions/UIResponderExtensions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 |
4 | extension UIResponder {
5 | private weak static var _currentFirstResponder: UIResponder?
6 |
7 | /// Current responder
8 | static var current: UIResponder? {
9 | UIResponder._currentFirstResponder = nil
10 | UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
11 | return UIResponder._currentFirstResponder
12 | }
13 |
14 | @objc internal func findFirstResponder(sender: AnyObject) {
15 | UIResponder._currentFirstResponder = self
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/Extensions/UIStackViewExtension.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIStackViewExtension.swift
3 | //
4 | //
5 | // Created by Ehab Alsharkawy on 03/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | extension UIStackView {
11 |
12 | func addArrangedSubviews(_ views: [UIView]) {
13 | views.forEach { addArrangedSubview($0) }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Extensions/URL+Extensions.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension URL {
4 |
5 | /// Instantiate a `URL` from a `StaticString.`
6 | ///
7 | /// https://www.swiftbysundell.com/articles/constructing-urls-in-swift/#static-urls
8 | /// - Parameter string: The URL string.
9 | /// - Precondition: The URL string must be valid.
10 | init(staticString string: StaticString) {
11 | guard let url = URL(string: "\(string)") else {
12 | preconditionFailure("Invalid static URL string: \(string)")
13 | }
14 |
15 | self = url
16 | }
17 |
18 | var withoutQuery: URL? {
19 | guard var urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: false) else {
20 | return nil
21 | }
22 |
23 | urlComponents.query = nil
24 | return urlComponents.url
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-amex.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-amex.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-blank.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-blank.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-diners.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-diners.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-discover.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-discover.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-jcb.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-jcb.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-mada.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-mada.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-maestro.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-maestro.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-mastercard.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-mastercard.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/Scheme/icon-visa.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "icon-visa.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/arrow_blue_right.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow_blue_right.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-next.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "keyboard-next@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "keyboard-next@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-next.imageset/keyboard-next@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/Source/Resources/Images.xcassets/keyboard-next.imageset/keyboard-next@2x.png
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-next.imageset/keyboard-next@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/Source/Resources/Images.xcassets/keyboard-next.imageset/keyboard-next@3x.png
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-previous.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "keyboard-previous@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "filename" : "keyboard-previous@3x.png",
14 | "idiom" : "universal",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-previous.imageset/keyboard-previous@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/Source/Resources/Images.xcassets/keyboard-previous.imageset/keyboard-previous@2x.png
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/keyboard-previous.imageset/keyboard-previous@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/Source/Resources/Images.xcassets/keyboard-previous.imageset/keyboard-previous@3x.png
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/left_arrow.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "left_arrow.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Source/Resources/Images.xcassets/warning.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "warning.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Source/Suppporting Files/CheckoutSdkIos.h:
--------------------------------------------------------------------------------
1 | //
2 | // FramesIos.h
3 | // FramesIos
4 | //
5 | // Created by Floriel Fedry on 20/04/2018.
6 | // Copyright © 2018 Checkout. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for FramesIos.
12 | FOUNDATION_EXPORT double FramesIosVersionNumber;
13 |
14 | //! Project version string for FramesIos.
15 | FOUNDATION_EXPORT const unsigned char FramesIosVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Source/Suppporting Files/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/AddressLine1/DefaultBillingFormAddressLine1CellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormAddressLine1CellStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.AddressLine1.title)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField()
10 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.AddressLine1.error)
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/AddressLine2/DefaultBillingFormAddressLine2CellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormAddressLine2CellStyle: CellTextFieldStyle {
4 | public var isMandatory = false
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.AddressLine2.title)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle? = DefaultTitleLabelStyle(
9 | backgroundColor: .clear,
10 | text: Constants.LocalizationKeys.optionalInput,
11 | font: FramesUIStyle.Font.bodySmall,
12 | textColor: FramesUIStyle.Color.textSecondary)
13 | public var textfield: ElementTextFieldStyle = DefaultTextField()
14 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.AddressLine2.error)
15 | }
16 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/City/DefaultBillingFormCityCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormCityCellStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.City.text)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField()
10 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.City.error)
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/Country/DefaultBillingFormCountryCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormCountryCellStyle: CellButtonStyle {
4 | public var backgroundColor: UIColor = .clear
5 | public var button: ElementButtonStyle = DefaultCountryFormButtonStyle()
6 | public var isMandatory = true
7 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.Country.text)
8 | public var hint: ElementStyle?
9 | public var mandatory: ElementStyle?
10 | public var error: ElementErrorViewStyle?
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/FullName/DefaultBillingFormFullNameCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormFullNameCellStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.FullName.text)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField()
10 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.FullName.error)
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/PhoneNumber/DefaultBillingFormPhoneNumberCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormPhoneNumberCellStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.PhoneNumber.text)
7 | public var hint: ElementStyle? = DefaultHintInputLabelStyle(isHidden: false, text: Constants.LocalizationKeys.BillingForm.PhoneNumber.hint)
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField(isSupportingNumericKeyboard: true)
10 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.PhoneNumber.error)
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/Postcode/DefaultBillingFormPostCodeCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormPostcodeCellStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.Postcode.text)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField()
10 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.Postcode.error)
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Fields/State/DefaultBillingFormStateCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormStateCellStyle: CellTextFieldStyle {
4 | public var isMandatory = false
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.State.text)
7 | public var hint: ElementStyle?
8 | public var mandatory: ElementStyle? = DefaultTitleLabelStyle(
9 | backgroundColor: .clear,
10 | text: Constants.LocalizationKeys.optionalInput,
11 | font: FramesUIStyle.Font.bodySmall,
12 | textColor: FramesUIStyle.Color.textSecondary)
13 | public var textfield: ElementTextFieldStyle = DefaultTextField()
14 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.BillingForm.State.error)
15 | }
16 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Header/Main/DefaultBillingFormHeaderCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormHeaderCellStyle: BillingFormHeaderCellStyle {
4 | public var backgroundColor: UIColor = .clear
5 | public var headerLabel: ElementStyle = DefaultHeaderLabelFormStyle(text: Constants.LocalizationKeys.BillingForm.Header.title)
6 | public var cancelButton: ElementButtonStyle = DefaultCancelButtonFormStyle()
7 | public var doneButton: ElementButtonStyle = DefaultDoneFormButtonStyle()
8 | }
9 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Header/Title/DefaultHeaderLabelFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultHeaderLabelFormStyle: ElementStyle {
4 | public var textAlignment: NSTextAlignment = .natural
5 | public var backgroundColor: UIColor = .clear
6 | public var isHidden = false
7 | public var text: String = ""
8 | public var font = FramesUIStyle.Font.title2
9 | public var textColor: UIColor = FramesUIStyle.Color.textPrimary
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/BillingForm/Main/DefaultBillingFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultBillingFormStyle: BillingFormStyle {
4 | public var mainBackground: UIColor = FramesUIStyle.Color.backgroundPrimary
5 | public var header: BillingFormHeaderCellStyle = DefaultBillingFormHeaderCellStyle()
6 | public var cells: [BillingFormCell] = FramesFactory.cellsStyleInOrder
7 |
8 | public init() {}
9 | }
10 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/Elements/Error/DefaultErrorInputLabelStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultErrorInputLabelStyle: ElementErrorViewStyle {
4 | public var textAlignment: NSTextAlignment = .natural
5 | public var isHidden = true
6 | public var backgroundColor: UIColor = .clear
7 | public var tintColor: UIColor = FramesUIStyle.Color.textError
8 | public var text: String = ""
9 | public var font = FramesUIStyle.Font.bodySmallPlus
10 | public var textColor: UIColor = FramesUIStyle.Color.textError
11 | public var image: UIImage? = Constants.Bundle.Images.warning.image
12 | public var height: Double = Constants.Style.BillingForm.InputErrorLabel.height.rawValue
13 | }
14 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/Elements/Hint/DefaultHintInputLabelStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultHintInputLabelStyle: ElementStyle {
4 | public var textAlignment: NSTextAlignment = .natural
5 | public var backgroundColor: UIColor = .clear
6 | public var isHidden = false
7 | public var text: String = ""
8 | public var font = FramesUIStyle.Font.bodySmall
9 | public var textColor: UIColor = FramesUIStyle.Color.textSecondary
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Default Implementation/Elements/Title/DefaultTitleLabelStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultTitleLabelStyle: ElementStyle {
4 | public var textAlignment: NSTextAlignment = .natural
5 | public var backgroundColor: UIColor = .clear
6 | public var isHidden = false
7 | public var text: String = ""
8 | public var font = FramesUIStyle.Font.inputLabel
9 | public var textColor: UIColor = FramesUIStyle.Color.textPrimary
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Model/BillingForm.swift:
--------------------------------------------------------------------------------
1 | import Checkout
2 |
3 | public struct BillingForm: Equatable {
4 | public let name: String?
5 | public let address: Address?
6 | public let phone: Phone?
7 |
8 | public init(name: String?, address: Address?, phone: Phone?) {
9 | self.name = name
10 | self.address = address
11 | self.phone = phone
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Style Protocol/BillingFormHeaderCellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol BillingFormHeaderCellStyle {
4 | var backgroundColor: UIColor { get }
5 | var headerLabel: ElementStyle { get }
6 | var cancelButton: ElementButtonStyle { get }
7 | var doneButton: ElementButtonStyle { get set }
8 | }
9 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/Style Protocol/BillingFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol BillingFormStyle {
4 | var mainBackground: UIColor { get }
5 | var header: BillingFormHeaderCellStyle { get set }
6 | var cells: [BillingFormCell] { get set }
7 | }
8 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/View/BillingFormTextField.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | protocol BillingFormTextField: UITextField {
4 | var type: BillingFormCell? { get set }
5 | }
6 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/View/MainBillingFormTextField.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | final class DefaultBillingFormTextField: UITextField, BillingFormTextField {
4 | var type: BillingFormCell?
5 |
6 | init(type: BillingFormCell?) {
7 | self.type = type
8 | super.init(frame: .zero)
9 | }
10 |
11 | required init?(coder: NSCoder) {
12 | fatalError("init(coder:) has not been implemented")
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Source/UI/BillingForm/ViewModel/BillingFormViewModel.swift:
--------------------------------------------------------------------------------
1 | import Checkout
2 |
3 | protocol BillingFormViewModelDelegate: AnyObject {
4 | func onTapDoneButton(data: BillingForm)
5 | func onTapCancelButton()
6 | func onBillingScreenShown()
7 | }
8 |
9 | protocol BillingFormViewModelEditingDelegate: AnyObject {
10 | func didFinishEditingBillingForm(successfully: Bool)
11 | }
12 |
13 | protocol BillingFormViewModel {
14 | var style: BillingFormStyle { get }
15 | var data: BillingForm? { get }
16 | var updateRows: (([Int]) -> Void)? { get set }
17 | func viewControllerWillAppear()
18 | }
19 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Cell/CellButtonStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol CellButtonStyle: CellStyle {
4 | var button: ElementButtonStyle { get set }
5 | }
6 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Cell/CellStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol CellStyle {
4 | var isMandatory: Bool { get }
5 | var backgroundColor: UIColor { get }
6 | var title: ElementStyle? { get }
7 | var mandatory: ElementStyle? { get }
8 | var hint: ElementStyle? { get }
9 | var error: ElementErrorViewStyle? { get set }
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Cell/CellTextFieldStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol CellTextFieldStyle: CellStyle {
4 | var textfield: ElementTextFieldStyle { get set }
5 | }
6 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Elements/ElementBorderStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol ElementBorderStyle {
4 | var cornerRadius: CGFloat { get set }
5 | var borderWidth: CGFloat { get set }
6 | var normalColor: UIColor { get set }
7 | var focusColor: UIColor { get set }
8 | var errorColor: UIColor { get set }
9 | var edges: UIRectEdge? { get set }
10 | var corners: UIRectCorner? { get set }
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Elements/ElementErrorViewStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol ElementErrorViewStyle: ElementStyle {
4 | var textColor: UIColor { get set }
5 | var backgroundColor: UIColor { get set }
6 | var tintColor: UIColor { get }
7 | var image: UIImage? { get }
8 | var height: Double { get }
9 | }
10 |
--------------------------------------------------------------------------------
/Source/UI/CommonUI/Protocols/Elements/ElementStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol ElementStyle {
4 | var textAlignment: NSTextAlignment { get set }
5 | var isHidden: Bool { get set }
6 | var text: String { get set }
7 | var font: UIFont { get set }
8 | var backgroundColor: UIColor { get set }
9 | var textColor: UIColor { get set }
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/CountrySelection/CountrySelectionViewControllerDelegate.swift:
--------------------------------------------------------------------------------
1 | import Checkout
2 |
3 | /// Method that you can use to handle the country selection by the user
4 | public protocol CountrySelectionViewControllerDelegate: AnyObject {
5 |
6 | /// Executed when an user select a country
7 | ///
8 | /// - parameter country: Country selected
9 | func onCountrySelected(country: Country)
10 | }
11 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/BillingFormSummary/Summary/View/DefaultAddBillingDetailsViewStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultAddBillingDetailsViewStyle: CellButtonStyle {
4 | public var mandatory: ElementStyle?
5 | public var backgroundColor: UIColor = .clear
6 | public var button: ElementButtonStyle = DefaultAddBillingDetailsButtonStyle()
7 | public var isMandatory = true
8 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.BillingForm.Header.title)
9 | public var hint: ElementStyle? = DefaultHintInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.BillingSummary.hint)
10 | public var error: ElementErrorViewStyle?
11 | }
12 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/CardNumber/DefaultCardNumberFormStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultCardNumberFormStyle.swift
3 | // Frames
4 | //
5 | // Created by Harry Brown on 27/06/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public struct DefaultCardNumberFormStyle: CellTextFieldStyle {
12 | public var isMandatory = true
13 | public var backgroundColor: UIColor = .clear
14 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.PaymentForm.CardNumber.title)
15 | public var hint: ElementStyle?
16 | public var mandatory: ElementStyle?
17 | public var textfield: ElementTextFieldStyle = DefaultTextField(isSupportingNumericKeyboard: true)
18 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.CardNumber.error)
19 | }
20 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/Cardholder/DefaultCardholderFormStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultCardholderFormStyle.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 16/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public struct DefaultCardholderFormStyle: CellTextFieldStyle {
11 | public var isMandatory = false
12 | public var backgroundColor: UIColor = .clear
13 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.PaymentForm.Cardholder.title)
14 | public var hint: ElementStyle?
15 | public var mandatory: ElementStyle? = DefaultTitleLabelStyle(
16 | backgroundColor: .clear,
17 | text: Constants.LocalizationKeys.optionalInput,
18 | font: FramesUIStyle.Font.bodySmall,
19 | textColor: FramesUIStyle.Color.textSecondary)
20 | public var textfield: ElementTextFieldStyle = DefaultTextField()
21 | public var error: ElementErrorViewStyle?
22 | }
23 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/DefaultPaymentFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultPaymentFormStyle: PaymentFormStyle {
4 | public var backgroundColor: UIColor = FramesUIStyle.Color.backgroundPrimary
5 | public var headerView: PaymentHeaderCellStyle = DefaultPaymentHeaderCellStyle()
6 | public var editBillingSummary: BillingSummaryViewStyle? = DefaultBillingSummaryViewStyle()
7 | public var addBillingSummary: CellButtonStyle? = DefaultAddBillingDetailsViewStyle()
8 | public var cardholderInput: CellTextFieldStyle? = DefaultCardholderFormStyle()
9 | public var cardNumber: CellTextFieldStyle = DefaultCardNumberFormStyle()
10 | public var expiryDate: CellTextFieldStyle = DefaultExpiryDateFormStyle()
11 | public var securityCode: CellTextFieldStyle? = DefaultSecurityCodeFormStyle()
12 | public var payButton: ElementButtonStyle = DefaultPayButtonFormStyle()
13 |
14 | public init() { }
15 | }
16 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/ExpiryDate/DefaultExpiryDateFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public struct DefaultExpiryDateFormStyle: CellTextFieldStyle {
4 | public var isMandatory = true
5 | public var backgroundColor: UIColor = .clear
6 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.PaymentForm.ExpiryDate.title)
7 | public var hint: ElementStyle? = DefaultHintInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.ExpiryDate.hint)
8 | public var mandatory: ElementStyle?
9 | public var textfield: ElementTextFieldStyle = DefaultTextField(
10 | isSupportingNumericKeyboard: true,
11 | placeholder: Constants.LocalizationKeys.PaymentForm.ExpiryDate.placeholder)
12 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.ExpiryDate.Error.invalid)
13 | }
14 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Default Implementation/SecurityCode/DefaultSecurityCodeFormStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DefaultSecurityCodeFormStyle.swift
3 | //
4 | //
5 | // Created by Ehab Alsharkawy on 07/07/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public struct DefaultSecurityCodeFormStyle: CellTextFieldStyle {
11 | public var isMandatory = true
12 | public var backgroundColor: UIColor = .clear
13 | public var title: ElementStyle? = DefaultTitleLabelStyle(text: Constants.LocalizationKeys.PaymentForm.SecurityCode.title)
14 | public var hint: ElementStyle? = DefaultHintInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.SecurityCode.hint)
15 | public var mandatory: ElementStyle?
16 | public var textfield: ElementTextFieldStyle = DefaultTextField(
17 | isSupportingNumericKeyboard: true)
18 | public var error: ElementErrorViewStyle? = DefaultErrorInputLabelStyle(text: Constants.LocalizationKeys.PaymentForm.SecurityCode.error)
19 | }
20 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/Model/PaymentStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaymentStyle.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 26/07/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | public struct PaymentStyle {
11 | let paymentFormStyle: PaymentFormStyle
12 | let billingFormStyle: BillingFormStyle?
13 |
14 | /**
15 | Define the payment form UI Styling
16 |
17 | - Parameters:
18 | - paymentFormStyle: UI Styling for the payment form, the root screen handling the payment
19 | - billingFormStyle: UI Styling for the billing form if the user will interact with the address billing
20 | */
21 | public init(paymentFormStyle: PaymentFormStyle,
22 | billingFormStyle: BillingFormStyle? = nil) {
23 | self.paymentFormStyle = paymentFormStyle
24 | self.billingFormStyle = billingFormStyle
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/StyleProtocol/PaymentFormStyle.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | public protocol PaymentFormStyle {
4 | var backgroundColor: UIColor { get set }
5 | var editBillingSummary: BillingSummaryViewStyle? { get set }
6 | var addBillingSummary: CellButtonStyle? { get set }
7 | var cardholderInput: CellTextFieldStyle? { get set }
8 | var cardNumber: CellTextFieldStyle { get set }
9 | var expiryDate: CellTextFieldStyle { get set }
10 | var securityCode: CellTextFieldStyle? { get set }
11 | var payButton: ElementButtonStyle { get set }
12 | var headerView: PaymentHeaderCellStyle { get set }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/StyleProtocol/PaymentHeaderCellStyle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PaymentHeaderCellStyle.swift
3 | // Frames
4 | //
5 | // Created by Ehab Alsharkawy
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | public protocol PaymentHeaderCellStyle {
12 | var shouldHideAcceptedCardsList: Bool { get }
13 | var backgroundColor: UIColor { get }
14 | var headerLabel: ElementStyle? { get }
15 | var subtitleLabel: ElementStyle? { get }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/UI/PaymentForm/View/CardholderName/CardholderViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CardholderViewModel.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 16/08/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | protocol CardholderDelegate: AnyObject {
11 | func cardholderUpdated(to cardholderInput: String)
12 | }
13 |
14 | final class CardholderViewModel {
15 |
16 | private enum Constants {
17 | static let inputAllowedCharacterSet = CharacterSet.letters.union([" ", "-", "'"])
18 | }
19 |
20 | weak var delegate: CardholderDelegate?
21 |
22 | func inputUpdated(to newInput: String) {
23 | delegate?.cardholderUpdated(to: newInput)
24 | }
25 |
26 | func isNewInputValid(_ string: String) -> Bool {
27 | Constants.inputAllowedCharacterSet
28 | .isSuperset(of: CharacterSet(charactersIn: string))
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Source/UI/Theme/BillingForm/Theme+BillingForm.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theme+BillingForm.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 18/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public extension Theme {
11 |
12 | /// Theme generated Billing Form Style
13 | struct ThemeBillingForm: BillingFormStyle {
14 | public var mainBackground: UIColor
15 | public var header: BillingFormHeaderCellStyle
16 | public var cells: [BillingFormCell]
17 | }
18 |
19 | /// Create a Billing Form from Styles defined for each sub component
20 | func buildBillingForm(header: ThemeBillingHeader,
21 | cells: [BillingFormCell]) -> ThemeBillingForm {
22 | ThemeBillingForm(mainBackground: self.backgroundColor,
23 | header: header,
24 | cells: cells)
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Source/UI/Theme/Generic/Theme+Border.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theme+Border.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 15/06/2023.
6 | //
7 |
8 | import UIKit
9 |
10 | public extension Theme {
11 |
12 | struct ThemeBorderStyle: ElementBorderStyle {
13 | public var cornerRadius: CGFloat
14 | public var borderWidth: CGFloat
15 | public var normalColor: UIColor
16 | public var focusColor: UIColor
17 | public var errorColor: UIColor
18 | public var edges: UIRectEdge?
19 | public var corners: UIRectCorner?
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/Source/UI/Theme/Generic/Theme+Mandatory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theme+Mandatory.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 09/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public extension Theme {
11 |
12 | /// Theme generated Mandatory style
13 | struct ThemeMandatory: ElementStyle {
14 | public var text: String
15 | public var textAlignment: NSTextAlignment = .natural
16 | public var isHidden = false
17 | public var font: UIFont
18 | public var backgroundColor: UIColor = .clear
19 | public var textColor: UIColor
20 | }
21 |
22 | /// Create a Mandatory Style from text
23 | func buildIsRequiredInput(text: String) -> ThemeMandatory {
24 | ThemeMandatory(text: text,
25 | font: titleFont,
26 | textColor: self.secondaryFontColor)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Source/UI/Theme/Generic/Theme+PageHeaderTitle.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theme+PageHeaderTitle.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 10/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public extension Theme {
11 |
12 | /// Theme generated Page Header Title
13 | struct ThemePageHeaderTitle: ElementStyle {
14 | public var isHidden = false
15 | public var text: String
16 | public var textAlignment: NSTextAlignment = .natural
17 | public var font: UIFont
18 | public var backgroundColor: UIColor = .clear
19 | public var textColor: UIColor
20 | }
21 |
22 | /// Create a Page Form Header Title from given text
23 | func buildPageHeaderTitle(text: String) -> ThemePageHeaderTitle {
24 | ThemePageHeaderTitle(text: text,
25 | font: headerFont,
26 | textColor: self.primaryFontColor)
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Source/UI/Theme/Generic/Theme+Title.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Theme+Title.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 09/08/2022.
6 | //
7 |
8 | import UIKit
9 |
10 | public extension Theme {
11 |
12 | /// Theme generated Title style
13 | struct ThemeTitle: ElementStyle {
14 | public var text: String
15 | public var textAlignment: NSTextAlignment = .natural
16 | public var isHidden = false
17 | public var font: UIFont
18 | public var backgroundColor: UIColor = .clear
19 | public var textColor: UIColor
20 | }
21 |
22 | /// Create a Title Style from text
23 | func buildTitle(text: String) -> ThemeTitle {
24 | ThemeTitle(text: text,
25 | font: titleFont,
26 | textColor: self.primaryFontColor)
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Source/UI/Validator/GenericInputValidator.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | class GenericInputValidator: Validator {
4 |
5 | func shouldAccept(text: String) -> Bool {
6 | true
7 | }
8 |
9 | func isValid(text: String) -> Bool {
10 | !text.isEmpty
11 | }
12 |
13 | func formatForDisplay(text: String) -> String {
14 | text
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Source/UI/Validator/Validator.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | protocol Validator {
4 | /// Determine whether the text should be an accepted input
5 | func shouldAccept(text: String) -> Bool
6 |
7 | /// Determine whether the text is a valid value
8 | func isValid(text: String) -> Bool
9 |
10 | /// Use validation to format for display
11 | func formatForDisplay(text: String) -> String
12 | }
13 |
--------------------------------------------------------------------------------
/Tests/Core/Extensions/DispatchQueue+DispatchingTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | @testable import Frames
4 |
5 | final class DispatchQueue_DispatchingTests: XCTestCase {
6 |
7 | func test_async_blockCalled() {
8 |
9 | let subject: Dispatching = DispatchQueue.main
10 |
11 | let expectation = XCTestExpectation(description: "Block called")
12 | subject.async(expectation.fulfill)
13 |
14 | wait(for: [expectation], timeout: 1.0)
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Tests/Core/Extensions/UIBarStyleTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIBarStyleTests.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 31/03/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Frames
11 |
12 | final class UIBarStyleTests: XCTestCase {
13 |
14 | func test_stringValue() {
15 | let testCases: [(UIBarStyle, String)] = [(.default, "default"),
16 | (.black, "black"),
17 | (.blackOpaque, "black"),
18 | (.blackTranslucent, "blackTranslucent")]
19 |
20 | testCases.forEach { subject, expectedValue in
21 | XCTAssertEqual(subject.stringValue, expectedValue, "expected \(expectedValue), received \(subject.stringValue) for \(subject)")
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tests/Core/Extensions/UIFont+PropertyProvidingTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIFont+PropertyProvidingTests.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 25/03/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Frames
11 |
12 | final class UIFontPropertyProvidingTests: XCTestCase {
13 | let font = UIFont.systemFont(ofSize: 12)
14 |
15 | func test_equality() {
16 | XCTAssertEqual(font.properties, font.properties)
17 | }
18 |
19 | func test_properties() {
20 | XCTAssertEqual(font.properties, [.size: 12.0, .name: ".SFUI-Regular"])
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Tests/Core/Extensions/URL+ExtensionsTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URL+ExtensionsTests.swift
3 | // Frames-Unit-Tests
4 | //
5 | // Created by Harry.Brown on 17/09/2021.
6 | //
7 |
8 | import XCTest
9 | @testable import Frames
10 |
11 | final class URL_ExtensionsTests: XCTestCase {
12 |
13 | func test_withoutQuery_withQuery() {
14 | let testURL = URL(string: "https://www.checkout.com/test/path?test=test_value")!
15 | let expectedResult = URL(string: "https://www.checkout.com/test/path")!
16 | let actualResult = testURL.withoutQuery
17 |
18 | XCTAssertEqual(actualResult, expectedResult)
19 | }
20 |
21 | func test_withoutQuery_withoutQuery() {
22 | let testURL = URL(string: "https://www.checkout.com/test/path")!
23 | let expectedResult = URL(string: "https://www.checkout.com/test/path")!
24 | let actualResult = testURL.withoutQuery
25 |
26 | XCTAssertEqual(actualResult, expectedResult)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/Core/Logging/CorrelationIDGeneratorTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | @testable import Frames
4 |
5 | final class CorrelationIDGeneratorTests: XCTestCase {
6 |
7 | // MARK: - generateCorrelationID
8 |
9 | func test_generateCorrelationID_returnsNonNilValue() throws {
10 | let subject = CorrelationIDManager()
11 | XCTAssertNotNil(subject.generateCorrelationID())
12 | }
13 |
14 | func test_generateCorrelationID_returnsCorrectValue_postDestroyCorrelationID() throws {
15 |
16 | let subject = CorrelationIDManager()
17 | XCTAssertNotNil(subject.generateCorrelationID())
18 | let temp = subject.generateCorrelationID()
19 | subject.destroyCorrelationID()
20 | XCTAssertNotEqual(subject.generateCorrelationID(), temp)
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/Tests/Fixtures/applePayToken.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "applepay",
3 | "token": "tok_ymu4qlccztkedmd6b7c3hcf6ae",
4 | "expires_on": "2019-10-21T10:48:35Z",
5 | "expiry_month": 8,
6 | "expiry_year": 2023,
7 | "scheme": "Visa",
8 | "last4": "6222",
9 | "bin": "481891",
10 | "card_type": "Debit",
11 | "card_category": "Consumer",
12 | "issuer": "HSBC BANK PLC",
13 | "issuer_country": "GB",
14 | "product_id": "F",
15 | "product_type": "Visa Classic"
16 | }
17 |
--------------------------------------------------------------------------------
/Tests/Fixtures/applePayTokenInvalid.json:
--------------------------------------------------------------------------------
1 | {
2 | "request_id": "0HL80RJLS76I7",
3 | "error_type": "request_invalid",
4 | "error_codes": [
5 | "payment_source_required"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/Tests/Fixtures/cardProviders.json:
--------------------------------------------------------------------------------
1 | {
2 | "object":"list",
3 | "count":6,
4 | "data":[
5 | {
6 | "id":"cp_1",
7 | "name":"VISA"
8 | },
9 | {
10 | "id":"cp_2",
11 | "name":"MASTERCARD"
12 | },
13 | {
14 | "id":"cp_3",
15 | "name":"AMEX"
16 | },
17 | {
18 | "id":"cp_4",
19 | "name":"DISCOVER"
20 | },
21 | {
22 | "id":"cp_5",
23 | "name":"DINERSCLUB"
24 | },
25 | {
26 | "id":"cp_6",
27 | "name":"JCB"
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/Tests/Fixtures/cardToken.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "card",
3 | "token": "tok_76km7r4p7woezcod36qki37iiu",
4 | "expires_on": "2018-06-01T14:35:09Z",
5 | "expiry_month": 6,
6 | "expiry_year": 2020,
7 | "name": "",
8 | "scheme": "Visa",
9 | "scheme_local": "Mada",
10 | "last4": "4242",
11 | "bin": "424242",
12 | "card_type": "Credit",
13 | "card_category": "Consumer",
14 | "issuer": "GOTHAM STATE BANK",
15 | "issuer_country": "US",
16 | "product_id": "A",
17 | "product_type": "Visa Traditional"
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/Fixtures/cardTokenBillingDetails.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "card",
3 | "token": "tok_76km7r4p7woezcod36qki37iiu",
4 | "expires_on": "2018-06-01T14:35:09Z",
5 | "expiry_month": 6,
6 | "expiry_year": 2020,
7 | "name": "",
8 | "scheme": "Visa",
9 | "scheme_local": "Mada",
10 | "last4": "4242",
11 | "bin": "424242",
12 | "card_type": "Credit",
13 | "card_category": "Consumer",
14 | "issuer": "GOTHAM STATE BANK",
15 | "issuer_country": "US",
16 | "product_id": "A",
17 | "product_type": "Visa Traditional",
18 | "billing_address" : {
19 | "address_line1": "Test Line1",
20 | "address_line2": "Test Line2",
21 | "city": "London",
22 | "state": "London",
23 | "zip": "N1 7LH",
24 | "country": "GB"
25 | },
26 | "phone": {
27 | "country_code": "+44",
28 | "number": "7456354812"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Tests/Fixtures/cardTokenInvalidNumber.json:
--------------------------------------------------------------------------------
1 | {
2 | "request_id": "3c3ad5a5-d513-44c9-92ae-f8d9b3557567",
3 | "error_type": "request_invalid",
4 | "error_codes": [
5 | "card_number_invalid"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Tests/Mocks/BillingFormViewModelEditingMockDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | @testable import Frames
3 |
4 | class BillingFormViewModelEditingMockDelegate: BillingFormViewModelEditingDelegate {
5 | var didFinishEditingBillingFormCalledTimes = 0
6 | var didFinishEditingBillingFormLastCalledWithSuccessfully: Bool?
7 |
8 | func didFinishEditingBillingForm(successfully: Bool) {
9 | didFinishEditingBillingFormCalledTimes += 1
10 | didFinishEditingBillingFormLastCalledWithSuccessfully = successfully
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Tests/Mocks/BillingFormViewModelMockDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Checkout
3 | @testable import Frames
4 |
5 | class BillingFormViewModelMockDelegate: BillingFormViewModelDelegate {
6 | var onTapDoneButtonCalledTimes = 0
7 | var onTapDoneButtonLastCalledWithData: BillingForm?
8 |
9 | var onTapCancelButtonCalledTimes = 0
10 |
11 | var updateCountryCodeCalledTimes = 0
12 | var updateCountryCodeLastCalledWithCode: Int?
13 |
14 | var onBillingScreenShownCounter = 0
15 |
16 | func onTapDoneButton(data: BillingForm) {
17 | onTapDoneButtonCalledTimes += 1
18 | onTapDoneButtonLastCalledWithData = data
19 | }
20 |
21 | func onTapCancelButton() {
22 | onTapCancelButtonCalledTimes += 1
23 | }
24 |
25 | func onBillingScreenShown() {
26 | onBillingScreenShownCounter += 1
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Tests/Mocks/CvvInputViewMockDelegate.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | @testable import Frames
3 |
4 | class CvvInputViewMockDelegate: UIViewController, UITextFieldDelegate {
5 |
6 | var calledTimes = 0
7 | var lastCalledWith: UITextField!
8 |
9 | func textFieldDidEndEditing(_ textField: UITextField) {
10 | calledTimes += 1
11 | lastCalledWith = textField
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockCardNumberViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockCardNumberViewModel.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 13/07/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | @testable import Frames
10 |
11 | final class MockCardNumberViewModel: CardNumberViewModelProtocol {
12 | private(set) var validateCalledWith: String?
13 | var validateToReturn: Constants.Bundle.SchemeIcon?
14 |
15 | private(set) var eagerValidateCalledWith: String?
16 | var eagerValidateToReturn: (newTextFieldValue: String, schemeIcon: Constants.Bundle.SchemeIcon)?
17 |
18 | func validate(cardNumber: String) -> Constants.Bundle.SchemeIcon? {
19 | validateCalledWith = cardNumber
20 | return validateToReturn
21 | }
22 |
23 | func eagerValidate(cardNumber: String) -> (newTextFieldValue: String, schemeIcon: Constants.Bundle.SchemeIcon)? {
24 | eagerValidateCalledWith = cardNumber
25 | return eagerValidateToReturn
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockCardNumberViewModelDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockCardNumberViewModelDelegate.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 08/07/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | @testable import Frames
10 | import Checkout
11 |
12 | final class MockCardNumberViewModelDelegate: CardNumberViewModelDelegate {
13 | private(set) var updateCalledWithValue: (cardNumber: String?, scheme: Card.Scheme)?
14 | private(set) var updateCalledWithError: CardNumberError?
15 |
16 | func update(result: Result) {
17 | switch result {
18 | case .failure(let error):
19 | updateCalledWithError = error
20 | case .success(let cardInfo):
21 | updateCalledWithValue = (cardInfo.cardNumber, cardInfo.scheme)
22 | }
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockCardholderDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockCardholderDelegate.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 18/08/2022.
6 | //
7 |
8 | import Foundation
9 | @testable import Frames
10 |
11 | final class MockCardholderDelegate: CardholderDelegate {
12 |
13 | var cardholderUpdatedReceivedArguments: [String] = []
14 | var cardhodlerUpdatedCompletion: (() -> Void)?
15 |
16 | func cardholderUpdated(to cardholderInput: String) {
17 | cardholderUpdatedReceivedArguments.append(cardholderInput)
18 | cardhodlerUpdatedCompletion?()
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockExpiryDateViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockExpiryDateViewDelegate.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 17/05/2023.
6 | //
7 |
8 | import Foundation
9 | import Checkout
10 | @testable import Frames
11 |
12 | final class MockExpiryDateViewDelegate: ExpiryDateViewDelegate {
13 |
14 | var receivedResults = [Result]()
15 |
16 | func update(result: Result) {
17 | receivedResults.append(result)
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockSecurityCodeDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockSecurityCodeDelegate.swift
3 | //
4 | //
5 | // Created by Alex Ioja-Yang on 28/07/2022.
6 | //
7 |
8 | @testable import Frames
9 | import XCTest
10 |
11 | class MockSecurityCodeDelegate: SecurityCodeViewModelDelegate {
12 |
13 | var schemeChangedCompletion = { XCTFail("Not setup to happen") }
14 |
15 | func schemeChanged() {
16 | schemeChangedCompletion()
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockThreeDSWKNavigationHelper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockThreeDSWKNavigationHelper.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 21/06/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | @testable import Checkout
11 |
12 | final class MockThreeDSWKNavigationHelper: NSObject, ThreeDSWKNavigationHelping {
13 | var delegate: ThreeDSWKNavigationHelperDelegate?
14 | }
15 |
--------------------------------------------------------------------------------
/Tests/Mocks/MockThreeDSWKNavigationHelperFactory.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockThreeDSWKNavigationHelperFactory.swift
3 | // FramesTests
4 | //
5 | // Created by Harry Brown on 21/06/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | @testable import Frames
11 | import Checkout
12 |
13 | final class MockThreeDSWKNavigationHelperFactory: ThreeDSWKNavigationHelperFactoryProtocol {
14 |
15 | private(set) var buildCalledWith: (successURL: URL?, failureURL: URL?)?
16 | var buildToReturn: ThreeDSWKNavigationHelping = MockThreeDSWKNavigationHelper()
17 | func build(successURL: URL?, failureURL: URL?) -> ThreeDSWKNavigationHelping {
18 | buildCalledWith = (successURL, failureURL)
19 | return buildToReturn
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/Mocks/NavigationControllerMock.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import UIKit
3 | @testable import Frames
4 |
5 | class MockNavigationController: UINavigationController {
6 |
7 | var pushedViewController: UIViewController?
8 |
9 | override func pushViewController(_ viewController: UIViewController, animated: Bool) {
10 | pushedViewController = viewController
11 | super.pushViewController(viewController, animated: true)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubCorrelationIDGenerator.swift:
--------------------------------------------------------------------------------
1 | @testable import Frames
2 |
3 | final class StubCorrelationIDManager: CorrelationIDManaging {
4 |
5 | var generateCorrelationIDReturnValue: String!
6 | var destroyCorrelationIDCalled = false
7 |
8 | func generateCorrelationID() -> String {
9 |
10 | return generateCorrelationIDReturnValue
11 | }
12 |
13 | func destroyCorrelationID() {
14 | destroyCorrelationIDCalled = true
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubDateProvider.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @testable import Frames
4 |
5 | final class StubDateProvider: DateProviding {
6 |
7 | var currentDateReturnValue: Date!
8 |
9 | var currentDate: Date {
10 |
11 | return currentDateReturnValue
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubDispatcher.swift:
--------------------------------------------------------------------------------
1 | @testable import Frames
2 |
3 | final class StubDispatcher: Dispatching {
4 |
5 | private(set) var asyncCalledWithBlock: (() -> Void)?
6 |
7 | func async(_ block: @escaping () -> Void) {
8 |
9 | asyncCalledWithBlock = block
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubError.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | enum StubError: CustomNSError {
4 |
5 | static let errorDomain = String(describing: Self.self)
6 |
7 | case errorOne
8 | case errorTwo
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubFramesEventLogger.swift:
--------------------------------------------------------------------------------
1 | @testable import Frames
2 | import CheckoutEventLoggerKit
3 |
4 | final class StubFramesEventLogger: FramesEventLogging {
5 |
6 | private(set) var logCalledWithFramesLogEvents: [FramesLogEvent] = []
7 | private(set) var addCalledWithMetadataPairs: [(metadata: String, key: CheckoutEventLogger.MetadataKey)] = []
8 |
9 | func log(_ framesLogEvent: FramesLogEvent) {
10 | logCalledWithFramesLogEvents.append(framesLogEvent)
11 | }
12 |
13 | func add(metadata: String, forKey key: CheckoutEventLogger.MetadataKey) {
14 | addCalledWithMetadataPairs.append((metadata, key))
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubJSONDecoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @testable import Frames
4 |
5 | final class StubJSONDecoder: JSONDecoder {
6 |
7 | private(set) var decodeCalledWithData: Data?
8 | var decodeThrownErrors: [Error] = []
9 | var decodeReturnValue: Any!
10 |
11 | override func decode(_ type: T.Type, from data: Data) throws -> T where T: Decodable {
12 |
13 | if !decodeThrownErrors.isEmpty {
14 | throw decodeThrownErrors.removeFirst()
15 | }
16 |
17 | decodeCalledWithData = data
18 | return decodeReturnValue as! T
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubJSONEncoder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @testable import Frames
4 |
5 | final class StubJSONEncoder: JSONEncoder {
6 |
7 | private(set) var encodeCalledWithValue: Any?
8 | var encodeReturnValue: Data!
9 |
10 | override func encode(_ value: T) throws -> Data where T: Encodable {
11 |
12 | encodeCalledWithValue = value
13 | return encodeReturnValue
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubUIDevice.swift:
--------------------------------------------------------------------------------
1 | @testable import Frames
2 |
3 | struct StubUIDevice: UIDevice {
4 |
5 | let modelName: String
6 | let systemVersion: String
7 | }
8 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubURLProtocol.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | final class StubURLProtocol: URLProtocol {
4 |
5 | static var responseData: [URL: Data] = [:]
6 |
7 | // MARK: - URLProtocol
8 |
9 | override final class func canInit(with request: URLRequest) -> Bool {
10 |
11 | return true
12 | }
13 |
14 | override final class func canonicalRequest(for request: URLRequest) -> URLRequest {
15 |
16 | return request
17 | }
18 |
19 | override func startLoading() {
20 |
21 | if let url = request.url, let data = Self.responseData[url] {
22 |
23 | client?.urlProtocol(self, didLoad: data)
24 | }
25 |
26 | client?.urlProtocolDidFinishLoading(self)
27 | }
28 |
29 | override func stopLoading() {
30 |
31 | // Required by the superclass.
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubURLSession.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | final class StubURLSession: URLSession {
4 |
5 | private(set) var dataTaskCalledWithRequest: URLRequest?
6 | private(set) var dataTaskCalledWithCompletionHandler: ((Data?, URLResponse?, Error?) -> Void)?
7 | var dataTaskReturnValue: URLSessionDataTask!
8 |
9 | override func dataTask(with request: URLRequest,
10 | completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
11 |
12 | dataTaskCalledWithRequest = request
13 | dataTaskCalledWithCompletionHandler = completionHandler
14 |
15 | return dataTaskReturnValue
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/Tests/Mocks/StubURLSessionDataTask.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | final class StubURLSessionDataTask: URLSessionDataTask {
4 |
5 | private(set) var resumeCalled = false
6 |
7 | override func resume() {
8 |
9 | resumeCalled = true
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/Tests/UI/Extension/UIStackViewExtensionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIStackViewExtensionTests.swift
3 | // iOS Example FrameUITests
4 | //
5 | // Created by Ehab Alsharkawy on 06/08/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Frames
11 |
12 | class UIStackViewExtensionTests: XCTestCase {
13 |
14 | func testAddArrangedSubviews() {
15 | let view1 = UIView()
16 | let view2 = UIView()
17 | let view3 = UIView()
18 | let stackView = UIStackView()
19 |
20 | stackView.addArrangedSubviews([view1, view2, view3])
21 |
22 | XCTAssertEqual(stackView.arrangedSubviews[0], view1)
23 | XCTAssertEqual(stackView.arrangedSubviews[1], view2)
24 | XCTAssertEqual(stackView.arrangedSubviews[2], view3)
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/Tests/UI/Extension/UIViewExtensionTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIStackViewExtensionTests.swift
3 | // FramesTests
4 | //
5 | // Created by Ehab Alsharkawy on 08/08/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import Frames
11 |
12 | class UIViewExtensionTests: XCTestCase {
13 |
14 | func testRemoveArrangedSubviews() {
15 | let view1 = UIView()
16 | let view2 = UIView()
17 | let view3 = UIView()
18 | let stackView = UIStackView(arrangedSubviews: [view1, view2, view3])
19 | stackView.removeSubviews()
20 |
21 | XCTAssertEqual(stackView.arrangedSubviews.count, 0)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/ExportOptions.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | method
6 | app-store
7 | teamID
8 | E32XBQK4Q5
9 | uploadBitcode
10 |
11 | compileBitcode
12 |
13 | uploadSymbols
14 |
15 | signingStyle
16 | manual
17 | signingCertificate
18 | iOS Distribution
19 | provisioningProfiles
20 |
21 | com.checkout.iOS-Example-Frame-SPM
22 | AppStoreValidationFrames-Automated
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.6
2 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
3 | import PackageDescription
4 | let package = Package()
5 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
6 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/Helpers/Helper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Helper.swift
3 | // iOS Example Frame Regression Tests
4 | //
5 | // Created by Okhan Okbay on 10/08/2023.
6 | // Copyright © 2023 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | enum Helper {
12 | static func wait() {
13 | let _ = XCTWaiter.wait(for: [XCTestExpectation()], timeout: 0.2)
14 | }
15 | }
16 |
17 | let snapshotPrecision: Float = 0.98
18 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/Helpers/Language.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Language.swift
3 | // iOS Example Frame Regression Tests
4 | //
5 | // Created by Okhan Okbay on 10/08/2023.
6 | // Copyright © 2023 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Language: String, CaseIterable {
12 | case fr, es, it, de, nl, ar, ro, en
13 |
14 | var locale: String {
15 | switch self {
16 | case .fr: return "fr_FR"
17 | case .es: return "es_ES"
18 | case .it: return "it_IT"
19 | case .de: return "de_DE"
20 | case .nl: return "nl_NL"
21 | case .ar: return "ar_SA"
22 | case .ro: return "ro_RO"
23 | case .en: return "en_US"
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/Helpers/StaticTexts.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StaticTexts.swift
3 | // iOS Example Frame Regression Tests
4 | //
5 | // Created by Okhan Okbay on 25/07/2023.
6 | // Copyright © 2023 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum StaticTexts {
12 | static let cardNumberNotValidError = "Please enter a valid card number"
13 | static let expiryDateIsInThePastError = "Expiry date is in the past"
14 | static let expiryDateIsNotValidError = "Please enter a valid expiry date"
15 | static let securityCodeNotValidError = "Please enter a valid security code"
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/Helpers/XCUIElement+TestHelpers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XCUIElement+TestHelpers.swift
3 | // iOS Example Frame Regression Tests
4 | //
5 | // Created by Okhan Okbay on 19/07/2023.
6 | // Copyright © 2023 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | extension XCUIElement {
12 |
13 | func contains(text: String) -> Bool {
14 | let predicate = NSPredicate(format: "label CONTAINS[c] %@", text)
15 | let elementQuery = staticTexts.containing(predicate)
16 | return elementQuery.count > 0
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.10.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.11.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.2.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.3.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.4.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.5.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.6.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.7.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.8.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardSchemeFormatSnapshotTests/testCardFormatting.9.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.2.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.3.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.4.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.5.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.6.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.7.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Failure.8.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testCardNumber_Success.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.2.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.3.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.4.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.5.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.6.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.7.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Failure.8.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/testSecurityCode_Success.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.2.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.3.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.4.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.5.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.6.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.7.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_InThePast_Failure.8.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.1.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.2.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.3.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.4.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.5.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.6.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.7.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Invalid_Failure.8.png
--------------------------------------------------------------------------------
/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame SPM/iOS Example Frame Regression Tests/__Snapshots__/CardValidationSnapshotTests/test_ExpiryDate_Success.1.png
--------------------------------------------------------------------------------
/iOS Example Frame/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.6
2 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
3 | import PackageDescription
4 | let package = Package()
5 | // THIS IS TO EXCLUDE SAMPLE PROJECTS FROM PACKAGE DISTRIBUTION
6 |
--------------------------------------------------------------------------------
/iOS Example Frame/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | platform :ios, '13.0'
3 |
4 | target 'iOS Example Frame' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for iOS Example Custom
9 | pod 'Frames', '4.3.8'
10 | end
11 |
12 | post_install do |installer|
13 | installer.pods_project.targets.each do |target|
14 | target.build_configurations.each do |config|
15 | config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/100.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/114.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/120.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/144.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/152.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/167.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/180.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/20.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/29.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/40.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/50.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/57.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/58.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/60.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/72.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/76.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/80.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/AppIcon.appiconset/87.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/amex-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "amex-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/apple-pay.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "apple-pay.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/arrow_blue_right.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow_blue_right.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/arrow_green_down.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "arrow_green_down.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/checkout-logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "checkout-logo.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/cloud-key.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "cloud.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/cloud-key.imageset/cloud.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/cloud-key.imageset/cloud.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/diners-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "diners-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/discover-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "discover-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/jcb-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "jcb-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-next.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "scale" : "2x"
10 | },
11 | {
12 | "filename" : "keyboard-next@3x.png",
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-next.imageset/keyboard-next@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-next.imageset/keyboard-next@3x.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous-1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "keyboard-previous@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous-1.imageset/keyboard-previous@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous-1.imageset/keyboard-previous@2x.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "filename" : "keyboard-previous@2x.png",
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous.imageset/keyboard-previous@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Assets.xcassets/keyboard-previous.imageset/keyboard-previous@2x.png
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/mada-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mada-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/maestro-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "maestro-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/mastercard-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "mastercard-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/new-experince.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "new.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/old-experince.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "old.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/visa-icon.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "visa-icon.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | },
12 | "properties" : {
13 | "preserves-vector-representation" : true,
14 | "template-rendering-intent" : "original"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Assets.xcassets/warning.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "warning.pdf",
5 | "idiom" : "universal"
6 | }
7 | ],
8 | "info" : {
9 | "author" : "xcode",
10 | "version" : 1
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Black.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Black.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-BlackItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-BlackItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Bold.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-BoldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-BoldItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Extralight.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Extralight.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-ExtralightItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-ExtralightItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Light.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Light.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-LightItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-LightItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Medium.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-MediumItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-MediumItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Regular.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-RegularItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-RegularItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Semibold.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-SemiboldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-SemiboldItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Super.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Super.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-SuperItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-SuperItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Thin.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-Thin.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-ThinItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Graphik/GraphikLCG-ThinItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Black.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-BlackItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-BlackItalic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-BoldItalic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Italic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Light.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-LightItalic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-MediumItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-MediumItalic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-Thin.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-ThinItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/Roboto/Roboto-ThinItalic.ttf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Bold.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-BoldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-BoldItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Heavy.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Heavy.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-HeavyItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-HeavyItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Light.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Light.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-LightItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-LightItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Medium.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-MediumItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-MediumItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Regular.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-RegularItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-RegularItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-Semibold.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-SemiboldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/checkout/frames-ios/7e4019f468c81f7b9212a3c148392ab46d25b0b5/iOS Example Frame/iOS Example Frame/Resources/Fonts/SF-Mono/SF-Mono-SemiboldItalic.otf
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/ar.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/de.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/de.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/en.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/en.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/es.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/es.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/fr.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/it.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/it.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/nl.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/nl.lproj/Main.strings:
--------------------------------------------------------------------------------
1 |
2 | /* Class = "UIButton"; normalTitle = "Go to payment page"; ObjectID = "T2l-21-qwk"; */
3 | "T2l-21-qwk.normalTitle" = "Go to payment page";
4 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Resources/ro.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Storyboards/ar-001.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Storyboards/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/Style/Style.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Style.swift
3 | // iOS Example Frame
4 | //
5 | // Created by Ehab Alsharkawy on 23/06/2022.
6 | // Copyright © 2022 Checkout. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum Style {
12 |
13 | static let paymentForm = PaymentFormStyleCustom1()
14 | static let billingForm = BillingFormStyleCustom1()
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example Frame/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/iOS Example Frame/iOS Example FrameUITests/Helpers/XCUIElement+TestHelpers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XCUIElement+TestHelpers.swift
3 | // iOS Example FrameUITests
4 | //
5 | // Created by Okhan Okbay on 26/10/2023.
6 | // Copyright © 2023 Checkout. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | extension XCUIElement {
12 |
13 | func contains(text: String) -> Bool {
14 | let predicate = NSPredicate(format: "label CONTAINS[c] %@", text)
15 | let elementQuery = staticTexts.containing(predicate)
16 | return elementQuery.count > 0
17 | }
18 | }
19 |
--------------------------------------------------------------------------------