├── .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 | --------------------------------------------------------------------------------