Browse Source

Add a close button to the premium paywall.

Give pro users a round bordered dismiss control with hover feedback so they can close the subscription page without using Continue with free plan.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 1 month ago
parent
commit
0f234ce589
1 changed files with 75 additions and 0 deletions
  1. 75 0
      smart_printer/PaywallView.swift

+ 75 - 0
smart_printer/PaywallView.swift

@@ -748,6 +748,65 @@ private final class PaywallTrustItemView: NSView, AppearanceRefreshable {
     }
 }
 
+// MARK: - Close Button
+
+private final class PaywallCloseButton: NSButton, AppearanceRefreshable {
+    private var hoverTracker: HoverTracker?
+    private var isHovered = false
+
+    init() {
+        super.init(frame: .zero)
+        isBordered = false
+        bezelStyle = .inline
+        translatesAutoresizingMaskIntoConstraints = false
+        wantsLayer = true
+        layer?.cornerRadius = 15
+        layer?.borderWidth = 1.5
+        if let image = NSImage(systemSymbolName: "xmark", accessibilityDescription: "Close") {
+            let config = NSImage.SymbolConfiguration(pointSize: 12, weight: .semibold)
+            self.image = image.withSymbolConfiguration(config)
+        }
+        refreshAppearance()
+
+        hoverTracker = HoverTracker(view: self) { [weak self] hovering in
+            self?.setHovered(hovering)
+        }
+    }
+
+    @available(*, unavailable)
+    required init?(coder: NSCoder) { nil }
+
+    func refreshAppearance() {
+        updateAppearance()
+    }
+
+    private func setHovered(_ hovering: Bool) {
+        isHovered = hovering
+        animateHover {
+            updateAppearance()
+            layer?.transform = hovering
+                ? CATransform3DMakeScale(1.06, 1.06, 1)
+                : CATransform3DIdentity
+        }
+    }
+
+    private func updateAppearance() {
+        if isHovered {
+            layer?.backgroundColor = AppTheme.elevatedBackground.cgColor
+            layer?.borderColor = AppTheme.paywallAccent.withAlphaComponent(0.45).cgColor
+            contentTintColor = AppTheme.textPrimary
+        } else {
+            layer?.backgroundColor = AppTheme.paywallTrustBackground.cgColor
+            layer?.borderColor = AppTheme.paywallBorder.cgColor
+            contentTintColor = AppTheme.textSecondary
+        }
+    }
+
+    override func resetCursorRects() {
+        addCursorRect(bounds, cursor: .pointingHand)
+    }
+}
+
 // MARK: - CTA Button
 
 private final class PaywallCTAButton: NSButton, AppearanceRefreshable {
@@ -802,6 +861,7 @@ final class PaywallView: NSView, AppearanceRefreshable {
     private let ctaButton = PaywallCTAButton()
     private let continueFreePlanLink = PaywallFooterLink(title: "Continue with free plan")
     private let manageSubscriptionLink = PaywallFooterLink(title: "Manage Subscription")
+    private let premiumCloseButton = PaywallCloseButton()
     private var primaryFooterLinkCell: NSView?
     private var leftPanelTitle: NSTextField!
     private var rightTitle: NSTextField!
@@ -860,6 +920,7 @@ final class PaywallView: NSView, AppearanceRefreshable {
         let isPro = StoreManager.shared.isPro
         continueFreePlanLink.isHidden = isPro
         manageSubscriptionLink.isHidden = !isPro
+        premiumCloseButton.isHidden = !isPro
         primaryFooterLinkCell?.needsLayout = true
         primaryFooterLinkCell?.layoutSubtreeIfNeeded()
     }
@@ -886,8 +947,13 @@ final class PaywallView: NSView, AppearanceRefreshable {
         let leftPanel = makeLeftPanel()
         let rightPanel = makeRightPanel()
 
+        premiumCloseButton.target = self
+        premiumCloseButton.action = #selector(premiumCloseTapped)
+        premiumCloseButton.isHidden = true
+
         addSubview(leftPanel)
         addSubview(rightPanel)
+        addSubview(premiumCloseButton)
 
         NSLayoutConstraint.activate([
             leftPanel.leadingAnchor.constraint(equalTo: leadingAnchor),
@@ -899,6 +965,11 @@ final class PaywallView: NSView, AppearanceRefreshable {
             rightPanel.trailingAnchor.constraint(equalTo: trailingAnchor),
             rightPanel.topAnchor.constraint(equalTo: topAnchor),
             rightPanel.bottomAnchor.constraint(equalTo: bottomAnchor),
+
+            premiumCloseButton.topAnchor.constraint(equalTo: topAnchor, constant: 16),
+            premiumCloseButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
+            premiumCloseButton.widthAnchor.constraint(equalToConstant: 30),
+            premiumCloseButton.heightAnchor.constraint(equalToConstant: 30),
         ])
     }
 
@@ -1195,6 +1266,10 @@ final class PaywallView: NSView, AppearanceRefreshable {
         onClose?()
     }
 
+    @objc private func premiumCloseTapped() {
+        onClose?()
+    }
+
     @objc private func manageSubscriptionTapped() {
         StoreManager.shared.showManageSubscriptions()
     }