Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to toggle edit mode for vertical mode #3576

Merged
merged 21 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@
6103F2BC2BE45990002D67F8 /* SavedPaymentMethodManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6103F2BB2BE45990002D67F8 /* SavedPaymentMethodManager.swift */; };
614A8AE72BE53C6900E8688B /* SavedPaymentMethodManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6103F2BD2BE53737002D67F8 /* SavedPaymentMethodManagerTest.swift */; };
6151DDC02B14FDCF00ED4F7E /* UpdateCardViewControllerSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6151DDBF2B14FDCF00ED4F7E /* UpdateCardViewControllerSnapshotTests.swift */; };
6198AA6C2BED1AC000F39D3E /* CheckmarkCircleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6198AA6B2BED1AC000F39D3E /* CheckmarkCircleView.swift */; };
6198AA6E2BED1C5A00F39D3E /* PaymentMethodRowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6198AA6D2BED1C5A00F39D3E /* PaymentMethodRowButton.swift */; };
61C0D3B8C63EB4558AB74A7E /* StripePayments.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A1C7CFA5C9C1A8A73CFA1C0 /* StripePayments.framework */; };
61CB0BD02BED985100E24A4C /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61CBE6672BED97EE005F7FEB /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift */; };
Expand Down Expand Up @@ -433,7 +432,6 @@
6151DDBF2B14FDCF00ED4F7E /* UpdateCardViewControllerSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCardViewControllerSnapshotTests.swift; sourceTree = "<group>"; };
617C44F9338DE2E93E318291 /* PayWithLinkWebController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PayWithLinkWebController.swift; sourceTree = "<group>"; };
6193FC5E14E1EC459E31B5F4 /* SheetNavigationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetNavigationButton.swift; sourceTree = "<group>"; };
6198AA6B2BED1AC000F39D3E /* CheckmarkCircleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckmarkCircleView.swift; sourceTree = "<group>"; };
6198AA6D2BED1C5A00F39D3E /* PaymentMethodRowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaymentMethodRowButton.swift; sourceTree = "<group>"; };
61CBE6652BED9749005F7FEB /* VerticalSavedPaymentMethodsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalSavedPaymentMethodsViewController.swift; sourceTree = "<group>"; };
61CBE6672BED97EE005F7FEB /* VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VerticalSavedPaymentMethodsViewControllerSnapshotTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -836,7 +834,6 @@
children = (
61CBE6652BED9749005F7FEB /* VerticalSavedPaymentMethodsViewController.swift */,
6198AA6D2BED1C5A00F39D3E /* PaymentMethodRowButton.swift */,
6198AA6B2BED1AC000F39D3E /* CheckmarkCircleView.swift */,
);
path = "Vertical Saved Payment Method Screen";
sourceTree = "<group>";
Expand Down Expand Up @@ -1704,7 +1701,6 @@
F42DEC1850964E75ACAC29AB /* CustomerSheet+API.swift in Sources */,
50C68C68B007A926BE99B2B8 /* CustomerSheet+PaymentMethodAvailability.swift in Sources */,
DB8A4C5FC11D0EED55E8C975 /* CustomerSheet+SwiftUI.swift in Sources */,
6198AA6C2BED1AC000F39D3E /* CheckmarkCircleView.swift in Sources */,
648FDD85FD6ECDA1BBC71D45 /* CustomerSheet.swift in Sources */,
9E77F1E9F801AE970F1A5BE1 /* CustomerSheetConfiguration.swift in Sources */,
AB8E1556F008083257A99E91 /* CustomerSheetError.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@
/* iDEAL bank section title for iDEAL form entry. */
"iDEAL Bank" = "iDEAL Bank";

/* Title shown above a view containing the customer's payment methods that they can delete or update */
"Manage payment methods" = "Manage payment methods";

/* Title shown above a carousel containing the customer's payment methods */
"Manage your payment methods" = "Manage your payment methods";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,11 @@ extension String.Localized {
"Select your payment method",
"Title shown above a carousel containing the customer's payment methods")
}

static var manage_payment_methods: String {
STPLocalizedString(
"Manage payment methods",
"Title shown above a view containing the customer's payment methods that they can delete or update"
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class CustomerSavedPaymentMethodsViewController: UIViewController {
self.navigationBar.additionalButton.removeTarget(
self, action: #selector(didSelectEditSavedPaymentMethodsButton),
for: .touchUpInside)
return shouldShowPaymentMethodCarousel ? .back : .close(showAdditionalButton: false)
return shouldShowPaymentMethodCarousel ? .back(showAdditionalButton: false) : .close(showAdditionalButton: false)
}
}())
}
Expand Down Expand Up @@ -664,7 +664,6 @@ class CustomerSavedPaymentMethodsViewController: UIViewController {
// MARK: Helpers
func configureEditSavedPaymentMethodsButton() {
if savedPaymentOptionsViewController.isRemovingPaymentMethods {
navigationBar.additionalButton.setTitle(UIButton.doneButtonTitle, for: .normal)
UIView.animate(withDuration: PaymentSheetUI.defaultAnimationDuration) {
self.actionButton.setHiddenIfNecessary(true)
self.updateBottomNotice()
Expand All @@ -675,10 +674,8 @@ class CustomerSavedPaymentMethodsViewController: UIViewController {
self.actionButton.setHiddenIfNecessary(!showActionButton)
self.updateBottomNotice()
}
navigationBar.additionalButton.setTitle(UIButton.editButtonTitle, for: .normal)
}
navigationBar.additionalButton.accessibilityIdentifier = "edit_saved_button"
navigationBar.additionalButton.titleLabel?.adjustsFontForContentSizeCategory = true
navigationBar.additionalButton.configureCommonEditButton(isEditingPaymentMethods: savedPaymentOptionsViewController.isRemovingPaymentMethods)
navigationBar.additionalButton.addTarget(
self, action: #selector(didSelectEditSavedPaymentMethodsButton), for: .touchUpInside)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,10 @@ extension SavedPaymentMethodCollectionView {
}
}

override var intrinsicContentSize: CGSize {
return CGSize(width: 20, height: 20)
}

required init(icon: Image, fillColor: UIColor) {
imageView = UIImageView(image: icon.makeImage(template: true))
super.init(frame: .zero)
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,64 +12,109 @@ import Foundation
import UIKit

protocol PaymentMethodRowButtonDelegate: AnyObject {
func didSelectButton(_ button: PaymentMethodRowButton)
// TODO(porter) Add did delete and did update
func didSelectButton(_ button: PaymentMethodRowButton, with paymentMethod: STPPaymentMethod)
func didSelectRemoveButton(_ button: PaymentMethodRowButton, with paymentMethod: STPPaymentMethod)
func didSelectEditButton(_ button: PaymentMethodRowButton, with paymentMethod: STPPaymentMethod)
}

final class PaymentMethodRowButton: UIView {

struct ViewModel {
let appearance: PaymentSheet.Appearance
let text: String
let image: UIImage
let paymentMethod: STPPaymentMethod
// TODO(porter) Add can remove and can update
}

enum State {
case selected
case unselected
case editing
}

// MARK: Internal properties
// TODO(porter) Maybe expand this into an enum of (selected, unselected, editing) state
var state: State = .unselected {
didSet {
previousState = oldValue

selectionTapGesture.isEnabled = !isEditing
shadowRoundedRect.isSelected = isSelected
circleView.isHidden = !isSelected
editButton.isHidden = !isEditing // TODO(porter) only show if we can edit
removeButton.isHidden = !isEditing // TOOD(porter) only show if we can remove
}
}

private(set) var previousState: State = .unselected

var isSelected: Bool {
get {
return shadowRoundedRect.isSelected
switch state {
case .selected:
return true
case .unselected, .editing:
return false
}
}

set {
shadowRoundedRect.isSelected = newValue
circleView.alpha = newValue ? 1.0 : 0.0
var isEditing: Bool {
switch state {
case .selected, .unselected:
return false
case .editing:
return true
}
}

weak var delegate: PaymentMethodRowButtonDelegate?

// MARK: Private properties
private let viewModel: ViewModel
private let paymentMethod: STPPaymentMethod
private let appearance: PaymentSheet.Appearance

// MARK: Private views

private lazy var paymentMethodImageView: UIImageView = {
let imageView = UIImageView(image: viewModel.image)
let imageView = UIImageView(image: paymentMethod.makeSavedPaymentMethodRowImage())
imageView.contentMode = .scaleAspectFit
// TODO(porter) Do we want to round the corners?
return imageView
}()

private lazy var label: UILabel = {
let label = UILabel()
label.text = viewModel.text
label.font = viewModel.appearance.scaledFont(for: viewModel.appearance.font.base.medium,
label.text = paymentMethod.paymentSheetLabel
label.font = appearance.scaledFont(for: appearance.font.base.medium,
style: .callout,
maximumPointSize: 25)
label.adjustsFontForContentSizeCategory = true
return label
}()

private lazy var circleView: CheckmarkCircleView = {
let circleView = CheckmarkCircleView(fillColor: viewModel.appearance.colors.primary)
circleView.alpha = 0.0
// TODO(porter) Refactor CircleIconView out of SavedPaymentMethodCollectionView once it is deleted
private lazy var circleView: SavedPaymentMethodCollectionView.CircleIconView = {
let circleView = SavedPaymentMethodCollectionView.CircleIconView(icon: .icon_checkmark,
fillColor: appearance.colors.primary)
circleView.isHidden = true
return circleView
}()

lazy var removeButton: CircularButton = {
let removeButton = CircularButton(style: .remove, iconColor: .white)
removeButton.backgroundColor = appearance.colors.danger
removeButton.isHidden = true
removeButton.addTarget(self, action: #selector(handleRemoveButtonTapped), for: .touchUpInside)
return removeButton
}()

private lazy var editButton: CircularButton = {
let editButton = CircularButton(style: .edit, iconColor: .white)
editButton.backgroundColor = appearance.colors.icon
editButton.isHidden = true
editButton.addTarget(self, action: #selector(handleEditButtonTapped), for: .touchUpInside)
return editButton
}()

private lazy var stackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [paymentMethodImageView, label, UIView.spacerView, circleView])
let stackView = UIStackView(arrangedSubviews: [paymentMethodImageView, label, UIView.spacerView, circleView, editButton, removeButton])
stackView.axis = .horizontal
stackView.alignment = .center
stackView.translatesAutoresizingMaskIntoConstraints = false
Expand All @@ -78,19 +123,25 @@ final class PaymentMethodRowButton: UIView {
bottom: 12,
trailing: PaymentSheetUI.defaultPadding)
stackView.isLayoutMarginsRelativeArrangement = true
stackView.setCustomSpacing(12, after: paymentMethodImageView) // Hardcoded from figma
stackView.spacing = 12 // Hardcoded from figma

return stackView
}()

private lazy var shadowRoundedRect: ShadowedRoundedRectangle = {
let shadowRoundedRect = ShadowedRoundedRectangle(appearance: viewModel.appearance)
let shadowRoundedRect = ShadowedRoundedRectangle(appearance: appearance)
shadowRoundedRect.translatesAutoresizingMaskIntoConstraints = false
shadowRoundedRect.addAndPinSubview(stackView)
return shadowRoundedRect
}()

init(viewModel: ViewModel) {
self.viewModel = viewModel
private lazy var selectionTapGesture: UITapGestureRecognizer = {
return UITapGestureRecognizer(target: self, action: #selector(handleSelectionTap))
}()

init(paymentMethod: STPPaymentMethod, appearance: PaymentSheet.Appearance) {
self.paymentMethod = paymentMethod
self.appearance = appearance
super.init(frame: .zero)

addAndPinSubview(shadowRoundedRect)
Expand All @@ -99,19 +150,25 @@ final class PaymentMethodRowButton: UIView {
paymentMethodImageView.widthAnchor.constraint(equalToConstant: 25),
])
// TODO(porter) accessibility?
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
addGestureRecognizer(tapGesture)
addGestureRecognizer(selectionTapGesture)
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: Tap handlers
@objc private func handleTap() {
shadowRoundedRect.isSelected = true
circleView.alpha = 1.0
delegate?.didSelectButton(self)
@objc private func handleSelectionTap() {
state = .selected
delegate?.didSelectButton(self, with: paymentMethod)
}

@objc private func handleEditButtonTapped() {
delegate?.didSelectEditButton(self, with: paymentMethod)
}

@objc private func handleRemoveButtonTapped() {
delegate?.didSelectRemoveButton(self, with: paymentMethod)
}

}
Expand Down