Explorar o código

Refine settings upgrade flow for premium users.

Show Upgrade only for premium non-lifetime accounts, route it into a lifetime-focused paywall state, and surface the current active plan so users can continue to upgrade.

Made-with: Cursor
huzaifahayat12 hai 3 meses
pai
achega
d993315608
Modificáronse 1 ficheiros con 60 adicións e 4 borrados
  1. 60 4
      meetings_app/ViewController.swift

+ 60 - 4
meetings_app/ViewController.swift

@@ -30,6 +30,7 @@ private enum SettingsAction: Int {
     case support = 2
     case moreApps = 3
     case shareApp = 4
+    case upgrade = 5
 }
 
 private enum PremiumPlan: Int {
@@ -84,6 +85,13 @@ private final class StoreKitCoordinator {
     var onEntitlementsChanged: ((Bool) -> Void)?
 
     var hasPremiumAccess: Bool { !activeEntitlementProductIDs.isEmpty }
+    var hasLifetimeAccess: Bool { activeEntitlementProductIDs.contains(PremiumStoreProduct.lifetime) }
+    var activeNonLifetimePlan: PremiumPlan? {
+        activeEntitlementProductIDs
+            .compactMap { PremiumStoreProduct.plan(for: $0) }
+            .filter { $0 != .lifetime }
+            .max(by: { $0.rawValue < $1.rawValue })
+    }
 
     private var transactionUpdatesTask: Task<Void, Never>?
 
@@ -266,6 +274,7 @@ final class ViewController: NSViewController {
     private var paywallPriceLabels: [PremiumPlan: NSTextField] = [:]
     private var paywallSubtitleLabels: [PremiumPlan: NSTextField] = [:]
     private var paywallContinueEnabled = true
+    private var paywallUpgradeFlowEnabled = false
     private var hasCompletedInitialStoreKitSync = false
     private var hasPresentedLaunchPaywall = false
     private var hasViewAppearedOnce = false
@@ -316,10 +325,12 @@ final class ViewController: NSViewController {
         let popover = NSPopover()
         popover.behavior = .transient
         popover.animates = true
+        let showUpgradeInSettings = storeKitCoordinator.hasPremiumAccess && !storeKitCoordinator.hasLifetimeAccess
         popover.contentViewController = SettingsMenuViewController(
             palette: palette,
             typography: typography,
             darkModeEnabled: darkModeEnabled,
+            showUpgradeInSettings: showUpgradeInSettings,
             onToggleDarkMode: { [weak self] enabled in
                 self?.setDarkMode(enabled)
             },
@@ -737,6 +748,10 @@ private extension ViewController {
             NSPasteboard.general.clearContents()
             NSPasteboard.general.setString(urlString, forType: .string)
             showSimpleAlert(title: "Share App", message: "Link copied to clipboard:\n\(urlString)")
+        case .upgrade:
+            settingsPopover?.performClose(nil)
+            settingsPopover = nil
+            showPaywall(upgradeFlow: true, preferredPlan: .lifetime)
         }
     }
 
@@ -748,8 +763,13 @@ private extension ViewController {
         alert.runModal()
     }
 
-    private func showPaywall() {
+    private func showPaywall(upgradeFlow: Bool = false, preferredPlan: PremiumPlan? = nil) {
+        paywallUpgradeFlowEnabled = upgradeFlow
+        if let preferredPlan {
+            selectedPremiumPlan = preferredPlan
+        }
         if let existing = paywallWindow {
+            refreshPaywallStoreUI()
             animatePaywallPresentation(existing)
             existing.makeKeyAndOrderFront(nil)
             NSApp.activate(ignoringOtherApps: true)
@@ -866,6 +886,16 @@ private extension ViewController {
 
     private func paywallOfferText(for plan: PremiumPlan) -> String {
         if storeKitCoordinator.hasPremiumAccess {
+            if storeKitCoordinator.hasLifetimeAccess {
+                return "Lifetime premium is active on this Apple ID."
+            }
+            if paywallUpgradeFlowEnabled {
+                let currentPlanName = storeKitCoordinator.activeNonLifetimePlan?.displayName ?? "Premium"
+                if plan == .lifetime {
+                    return "Current plan: \(currentPlanName). Tap Continue to upgrade to Lifetime."
+                }
+                return "Current plan: \(currentPlanName). Select Lifetime to upgrade."
+            }
             return "Premium is active on this Apple ID."
         }
         let productID = PremiumStoreProduct.productID(for: plan)
@@ -1052,10 +1082,20 @@ private extension ViewController {
             paywallContinueButton?.alphaValue = 0.75
             return
         }
-        if storeKitCoordinator.hasPremiumAccess {
+        if storeKitCoordinator.hasLifetimeAccess {
             paywallContinueEnabled = false
             paywallContinueLabel?.stringValue = "Premium Active"
             paywallContinueButton?.alphaValue = 0.75
+        } else if paywallUpgradeFlowEnabled && storeKitCoordinator.hasPremiumAccess {
+            if selectedPremiumPlan == .lifetime {
+                paywallContinueEnabled = true
+                paywallContinueLabel?.stringValue = "Continue"
+                paywallContinueButton?.alphaValue = 1.0
+            } else {
+                paywallContinueEnabled = false
+                paywallContinueLabel?.stringValue = "Select Lifetime to Upgrade"
+                paywallContinueButton?.alphaValue = 0.75
+            }
         } else {
             paywallContinueEnabled = true
             paywallContinueLabel?.stringValue = "Continue"
@@ -2736,6 +2776,17 @@ private extension ViewController {
     }
 }
 
+private extension PremiumPlan {
+    var displayName: String {
+        switch self {
+        case .weekly: return "Weekly"
+        case .monthly: return "Monthly"
+        case .yearly: return "Yearly"
+        case .lifetime: return "Lifetime"
+        }
+    }
+}
+
 extension ViewController: NSTextFieldDelegate {
     func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
         if control === browseAddressField, commandSelector == #selector(NSResponder.insertNewline(_:)) {
@@ -2751,6 +2802,7 @@ extension ViewController: NSWindowDelegate {
         guard let closingWindow = notification.object as? NSWindow else { return }
         if closingWindow === paywallWindow {
             paywallWindow = nil
+            paywallUpgradeFlowEnabled = false
         }
     }
 }
@@ -3258,6 +3310,7 @@ private final class SettingsMenuViewController: NSViewController {
         palette: Palette,
         typography: Typography,
         darkModeEnabled: Bool,
+        showUpgradeInSettings: Bool,
         onToggleDarkMode: @escaping (Bool) -> Void,
         onAction: @escaping (SettingsAction) -> Void
     ) {
@@ -3266,7 +3319,7 @@ private final class SettingsMenuViewController: NSViewController {
         self.onToggleDarkMode = onToggleDarkMode
         self.onAction = onAction
         super.init(nibName: nil, bundle: nil)
-        self.view = makeView(darkModeEnabled: darkModeEnabled)
+        self.view = makeView(darkModeEnabled: darkModeEnabled, showUpgradeInSettings: showUpgradeInSettings)
     }
 
     @available(*, unavailable)
@@ -3278,7 +3331,7 @@ private final class SettingsMenuViewController: NSViewController {
         darkToggle?.state = enabled ? .on : .off
     }
 
-    private func makeView(darkModeEnabled: Bool) -> NSView {
+    private func makeView(darkModeEnabled: Bool, showUpgradeInSettings: Bool) -> NSView {
         let root = NSView()
         root.translatesAutoresizingMaskIntoConstraints = false
 
@@ -3312,6 +3365,9 @@ private final class SettingsMenuViewController: NSViewController {
         stack.addArrangedSubview(settingsActionRow(icon: "💬", title: "Support", action: .support))
         stack.addArrangedSubview(settingsActionRow(icon: "⋯", title: "More Apps", action: .moreApps))
         stack.addArrangedSubview(settingsActionRow(icon: "⤴︎", title: "Share App", action: .shareApp))
+        if showUpgradeInSettings {
+            stack.addArrangedSubview(settingsActionRow(icon: "⬆︎", title: "Upgrade", action: .upgrade))
+        }
 
         for v in stack.arrangedSubviews {
             v.widthAnchor.constraint(equalTo: stack.widthAnchor).isActive = true