From cfceb88247f67be3a72897a861b992893959da15 Mon Sep 17 00:00:00 2001 From: Nick Porter <88012362+porter-stripe@users.noreply.github.com> Date: Fri, 1 Apr 2022 13:24:05 -0600 Subject: [PATCH] Make navigation buttons in PaymentSheet have a tap target of 44x44 (#942) --- Stripe.xcodeproj/project.pbxproj | 4 ++++ Stripe/SheetNavigationBar.swift | 4 ++-- Stripe/SheetNavigationButton.swift | 34 ++++++++++++++++++++++++++++++ Stripe/UIKit+PaymentSheet.swift | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 Stripe/SheetNavigationButton.swift diff --git a/Stripe.xcodeproj/project.pbxproj b/Stripe.xcodeproj/project.pbxproj index 29e97daab05..3689c7d8807 100644 --- a/Stripe.xcodeproj/project.pbxproj +++ b/Stripe.xcodeproj/project.pbxproj @@ -495,6 +495,7 @@ 61C5FA73272348A000D73313 /* icon-pm-klarna@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 61C5FA71272348A000D73313 /* icon-pm-klarna@3x.png */; }; 61D0FBDA27A36A440006ED6E /* PayWithLinkViewController-UpdatePaymentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D0FBD927A36A440006ED6E /* PayWithLinkViewController-UpdatePaymentViewController.swift */; }; 61D30DB926D5B5F2002872DE /* TestModeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61D30DB826D5B5F2002872DE /* TestModeView.swift */; }; + 61DB49DC27F7787C001A436C /* SheetNavigationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DB49DB27F7787C001A436C /* SheetNavigationButton.swift */; }; 61DBE71E27308195008565C8 /* KlarnaHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DBE71D27308195008565C8 /* KlarnaHelper.swift */; }; 61DBE720273082EC008565C8 /* KlarnaHelperTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61DBE71F273082EC008565C8 /* KlarnaHelperTest.swift */; }; 61EA8CEE26DD84DF00B2879D /* Error+PaymentSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61EA8CED26DD84DF00B2879D /* Error+PaymentSheet.swift */; }; @@ -1486,6 +1487,7 @@ 61C5FA71272348A000D73313 /* icon-pm-klarna@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-pm-klarna@3x.png"; sourceTree = ""; }; 61D0FBD927A36A440006ED6E /* PayWithLinkViewController-UpdatePaymentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PayWithLinkViewController-UpdatePaymentViewController.swift"; sourceTree = ""; }; 61D30DB826D5B5F2002872DE /* TestModeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestModeView.swift; sourceTree = ""; }; + 61DB49DB27F7787C001A436C /* SheetNavigationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetNavigationButton.swift; sourceTree = ""; }; 61DBE71D27308195008565C8 /* KlarnaHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KlarnaHelper.swift; sourceTree = ""; }; 61DBE71F273082EC008565C8 /* KlarnaHelperTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KlarnaHelperTest.swift; sourceTree = ""; }; 61EA8CED26DD84DF00B2879D /* Error+PaymentSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Error+PaymentSheet.swift"; sourceTree = ""; }; @@ -2941,6 +2943,7 @@ 36F6120C254C88C0006656BD /* ConfirmButton.swift */, B6B4CB6725C33782002B8322 /* ShadowedRoundedRectangleView.swift */, 36F6120D254C88C0006656BD /* SheetNavigationBar.swift */, + 61DB49DB27F7787C001A436C /* SheetNavigationButton.swift */, 61D30DB826D5B5F2002872DE /* TestModeView.swift */, B6596AB9255B776C00F68826 /* UIKit+PaymentSheet.swift */, 61532EC927E1507200CBB253 /* Appearance+FontScaling.swift */, @@ -4282,6 +4285,7 @@ B68A9E672582B88400E904B5 /* PaymentSheetConfiguration.swift in Sources */, 3610621C2695199B00795224 /* STPPaymentMethodLink.swift in Sources */, 3111C3612527B62C00207E32 /* STPBackendAPIAdapter.swift in Sources */, + 61DB49DC27F7787C001A436C /* SheetNavigationButton.swift in Sources */, B6E40EA2254253E400A5BABD /* PanModalPresentable+LayoutHelpers.swift in Sources */, E69552D625CCDC0F00753FDA /* STPiDEALBank.swift in Sources */, B6926AE625267EEB001F208B /* STPInternalAPIResponseDecodable.swift in Sources */, diff --git a/Stripe/SheetNavigationBar.swift b/Stripe/SheetNavigationBar.swift index 6763d379e4f..31bb3c6482d 100644 --- a/Stripe/SheetNavigationBar.swift +++ b/Stripe/SheetNavigationBar.swift @@ -22,7 +22,7 @@ class SheetNavigationBar: UIView { static let height: CGFloat = 48 weak var delegate: SheetNavigationBarDelegate? fileprivate lazy var closeButton: UIButton = { - let button = UIButton(type: .custom) + let button = SheetNavigationButton(type: .custom) button.setImage(Image.icon_x_standalone.makeImage(template: true), for: .normal) button.tintColor = appearance.color.icon button.accessibilityLabel = String.Localized.close @@ -31,7 +31,7 @@ class SheetNavigationBar: UIView { }() fileprivate lazy var backButton: UIButton = { - let button = UIButton(type: .custom) + let button = SheetNavigationButton(type: .custom) button.setImage(Image.icon_chevron_left_standalone.makeImage(template: true), for: .normal) button.tintColor = appearance.color.icon button.accessibilityLabel = STPLocalizedString("Back", "Text for back button") diff --git a/Stripe/SheetNavigationButton.swift b/Stripe/SheetNavigationButton.swift new file mode 100644 index 00000000000..f9e96b0aff8 --- /dev/null +++ b/Stripe/SheetNavigationButton.swift @@ -0,0 +1,34 @@ +// +// SheetNavigationButton.swift +// StripeiOS +// +// Created by Nick Porter on 4/1/22. +// Copyright © 2022 Stripe, Inc. All rights reserved. +// + +import UIKit + +/// A simple button that increases the tap target for small buttons used in the navigation bar of PaymentSheet +/// /// For internal SDK use only +@objc(STP_Internal_SheetNavigationButton) +class SheetNavigationButton: UIButton { + + override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { + // increase the hit frame to be at least as big as `minimumHitArea` + let buttonSize = self.bounds.size + let widthToAdd = max(PaymentSheetUI.minimumHitArea.width - buttonSize.width, 0) + let heightToAdd = max(PaymentSheetUI.minimumHitArea.height - buttonSize.height, 0) + let largerFrame = self.bounds.insetBy(dx: -widthToAdd / 2, dy: -heightToAdd / 2) + + // perform hit test on larger frame + return largerFrame.contains(point) + } + + override init(frame: CGRect) { + super.init(frame: frame) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/Stripe/UIKit+PaymentSheet.swift b/Stripe/UIKit+PaymentSheet.swift index ac4f5bcfedc..5ea482ab4a1 100644 --- a/Stripe/UIKit+PaymentSheet.swift +++ b/Stripe/UIKit+PaymentSheet.swift @@ -25,6 +25,7 @@ enum PaymentSheetUI { /// The minimnum amount of time to spend processing before transitioning to success/failure static let minimumFlightTime: TimeInterval = 1 static let delayBetweenSuccessAndDismissal: TimeInterval = 1.5 + static let minimumHitArea = CGSize(width: 44, height: 44) static func makeHeaderLabel(appearance: PaymentSheet.Appearance) -> UILabel { let header = UILabel()