Skip to content

Commit

Permalink
feature: Implement new dismissal mechanisms for Drop-In (#1039)
Browse files Browse the repository at this point in the history
* Implement new dismissal mechanisms for DropIn

* pod update and minor changes

* renaming

* Pod update, string update

---------

Co-authored-by: Boris Nikolic <[email protected]>
Co-authored-by: Niall Quinn <[email protected]>
  • Loading branch information
3 people authored Nov 13, 2024
1 parent 7017bba commit e86d2e2
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 19 deletions.
56 changes: 43 additions & 13 deletions Debug App/Resources/Localized Views/Base.lproj/Main.storyboard

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class MerchantSessionAndSettingsViewController: UIViewController {
@IBOutlet weak var vaultPaymentsSwitch: UISwitch!
@IBOutlet weak var disableSuccessScreenSwitch: UISwitch!
@IBOutlet weak var disableErrorScreenSwitch: UISwitch!
@IBOutlet weak var gesturesDismissalSwitch: UISwitch!
@IBOutlet weak var closeButtonDismissalSwitch: UISwitch!
@IBOutlet weak var disableInitScreenSwitch: UISwitch!
@IBOutlet weak var enableCVVRecaptureFlowSwitch: UISwitch!

Expand Down Expand Up @@ -293,6 +295,9 @@ class MerchantSessionAndSettingsViewController: UIViewController {
}
}

gesturesDismissalSwitch.isOn = true // Default value
closeButtonDismissalSwitch.isOn = false // Default false

lineItemsStackView.removeAllArrangedSubviews()
lineItemsStackView.alignment = .fill
lineItemsStackView.distribution = .fill
Expand Down Expand Up @@ -621,10 +626,22 @@ class MerchantSessionAndSettingsViewController: UIViewController {
@IBAction func primerSDKButtonTapped(_ sender: Any) {
customDefinedApiKey = (apiKeyTextField.text ?? "").isEmpty ? nil : apiKeyTextField.text

let selectedDismissalMechanisms: [DismissalMechanism] = {
var mechanisms = [DismissalMechanism]()
if gesturesDismissalSwitch.isOn {
mechanisms.append(.gestures)
}
if closeButtonDismissalSwitch.isOn {
mechanisms.append(.closeButton)
}
return mechanisms
}()

let uiOptions = PrimerUIOptions(
isInitScreenEnabled: !disableInitScreenSwitch.isOn,
isSuccessScreenEnabled: !disableSuccessScreenSwitch.isOn,
isErrorScreenEnabled: !disableErrorScreenSwitch.isOn,
dismissalMechanism: selectedDismissalMechanisms,
theme: applyThemingSwitch.isOn ? CheckoutTheme.tropical : nil)

let mandateData = PrimerStripeOptions.MandateData.templateMandate(merchantName: "Primer Inc.")
Expand Down
12 changes: 11 additions & 1 deletion Sources/PrimerSDK/Classes/Data Models/PrimerSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,15 @@ public class PrimerCardPaymentOptions: Codable {

// MARK: - UI OPTIONS

public enum DismissalMechanism: Codable {
case gestures, closeButton
}

internal protocol PrimerUIOptionsProtocol {
var isInitScreenEnabled: Bool { get } // Default: true
var isSuccessScreenEnabled: Bool { get } // Default: true
var isErrorScreenEnabled: Bool { get } // Default: true
var dismissalMechanism: [DismissalMechanism] { get } // Default: .gestures
var theme: PrimerTheme { get }
}

Expand All @@ -257,21 +262,24 @@ public class PrimerUIOptions: PrimerUIOptionsProtocol, Codable {
public internal(set) var isInitScreenEnabled: Bool
public internal(set) var isSuccessScreenEnabled: Bool
public internal(set) var isErrorScreenEnabled: Bool
public internal(set) var dismissalMechanism: [DismissalMechanism]
public let theme: PrimerTheme

private enum CodingKeys: String, CodingKey {
case isInitScreenEnabled, isSuccessScreenEnabled, isErrorScreenEnabled, theme
case isInitScreenEnabled, isSuccessScreenEnabled, isErrorScreenEnabled, dismissalMechanism, theme
}

public init(
isInitScreenEnabled: Bool? = nil,
isSuccessScreenEnabled: Bool? = nil,
isErrorScreenEnabled: Bool? = nil,
dismissalMechanism: [DismissalMechanism]? = [.gestures],
theme: PrimerTheme? = nil
) {
self.isInitScreenEnabled = isInitScreenEnabled != nil ? isInitScreenEnabled! : true
self.isSuccessScreenEnabled = isSuccessScreenEnabled != nil ? isSuccessScreenEnabled! : true
self.isErrorScreenEnabled = isErrorScreenEnabled != nil ? isErrorScreenEnabled! : true
self.dismissalMechanism = dismissalMechanism ?? [.gestures]
self.theme = theme ?? PrimerTheme()
}

Expand All @@ -280,6 +288,7 @@ public class PrimerUIOptions: PrimerUIOptionsProtocol, Codable {
self.isInitScreenEnabled = try container.decode(Bool.self, forKey: .isInitScreenEnabled)
self.isSuccessScreenEnabled = try container.decode(Bool.self, forKey: .isSuccessScreenEnabled)
self.isErrorScreenEnabled = try container.decode(Bool.self, forKey: .isErrorScreenEnabled)
self.dismissalMechanism = try container.decode([DismissalMechanism].self, forKey: .dismissalMechanism)
self.theme = PrimerTheme()
}

Expand All @@ -288,6 +297,7 @@ public class PrimerUIOptions: PrimerUIOptionsProtocol, Codable {
try container.encode(isInitScreenEnabled, forKey: .isInitScreenEnabled)
try container.encode(isSuccessScreenEnabled, forKey: .isSuccessScreenEnabled)
try container.encode(isErrorScreenEnabled, forKey: .isErrorScreenEnabled)
try container.encode(dismissalMechanism, forKey: .dismissalMechanism)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class PrimerContainerViewController: PrimerViewController {
mockedNavigationBar.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
mockedNavigationBar.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
mockedNavigationBar.heightAnchor.constraint(equalToConstant: 44).isActive = true
mockedNavigationBar.addDismissButton()

addChild(childViewController)
scrollView.bounces = false
Expand Down Expand Up @@ -102,5 +103,4 @@ extension UIView {
leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: leading).isActive = true
trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: trailing).isActive = true
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,44 @@ class PrimerNavigationBar: PrimerView {
didSet {
rightBarButton?.tintColor = theme.text.system.color
rightBarButton?.setTitleColor(theme.text.system.color, for: .normal)
rightBarButton?.frame = CGRect(
x: 0, y: 0, width: rightView.bounds.size.width, height: rightView.bounds.size.height
)

// Remove any existing subviews from rightView
rightView.subviews.forEach { view in
view.removeFromSuperview()
}

if let rightBarButton = rightBarButton {
rightView.addSubview(rightBarButton)
rightBarButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
rightBarButton.leadingAnchor.constraint(equalTo: rightView.leadingAnchor),
rightBarButton.trailingAnchor.constraint(equalTo: rightView.trailingAnchor),
rightBarButton.topAnchor.constraint(equalTo: rightView.topAnchor),
rightBarButton.bottomAnchor.constraint(equalTo: rightView.bottomAnchor)
])
}
}
}

var leftBarButton: UIButton? {
didSet {
leftBarButton?.tintColor = theme.text.system.color
leftBarButton?.setTitleColor(theme.text.system.color, for: .normal)

// Remove any existing subviews from rightView
leftView.subviews.forEach { view in
view.removeFromSuperview()
}

if let leftBarButton = leftBarButton {
leftView.addSubview(leftBarButton)
leftBarButton.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
leftBarButton.leadingAnchor.constraint(equalTo: leftView.leadingAnchor),
leftBarButton.trailingAnchor.constraint(equalTo: leftView.trailingAnchor),
leftBarButton.topAnchor.constraint(equalTo: leftView.topAnchor),
leftBarButton.bottomAnchor.constraint(equalTo: leftView.bottomAnchor)
])
}
}
}
Expand Down Expand Up @@ -91,6 +119,21 @@ class PrimerNavigationBar: PrimerView {
PrimerUIManager.primerRootViewController?.popViewController()
}

func addDismissButton() {
// Add Close button to navigation bar
if PrimerSettings.current.uiOptions.dismissalMechanism.contains(.closeButton) {
let dismissButton = UIButton(type: .system)
dismissButton.setTitle(Strings.Generic.cancel, for: .normal)
dismissButton.setTitleColor(UIColor.gray, for: .disabled)
dismissButton.addTarget(self, action: #selector(didTapCloseButton), for: .touchUpInside)
rightBarButton = dismissButton
}
}

@objc private func didTapCloseButton() {
PrimerInternal.shared.dismiss()
}

private func setup() {
translatesAutoresizingMaskIntoConstraints = false
heightAnchor.constraint(equalToConstant: PrimerDimensions.NavigationBar.default).isActive = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ internal class PrimerRootViewController: PrimerViewController {
}

private func setupGestureRecognizers() {
guard PrimerSettings.current.uiOptions.dismissalMechanism.contains(.gestures) else { return }
self.tapGesture = UITapGestureRecognizer(
target: self,
action: #selector(dismissGestureRecognizerAction))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ internal class PrimerVoucherInfoPaymentViewController: PrimerFormViewController

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
(parent as? PrimerContainerViewController)?.mockedNavigationBar.rightBarButton = shareButton
(parent as? PrimerContainerViewController)?.mockedNavigationBar.leftBarButton = shareButton
}

}
Expand Down

0 comments on commit e86d2e2

Please sign in to comment.