|
|
@@ -612,17 +612,15 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
private enum PremiumPlan: String, CaseIterable {
|
|
|
- case weekly = "com.mqldev.zoomapp.premium.weekly"
|
|
|
- case monthly = "com.mqldev.zoomapp.premium.monthly"
|
|
|
- case yearly = "com.mqldev.zoomapp.premium.yearly"
|
|
|
- case lifetime = "com.mqldev.zoomapp.premium.lifetime"
|
|
|
+ case monthly = "com.account.zoom.monthly"
|
|
|
+ case biyearly = "com.account.zoom.biyearly"
|
|
|
+ case yearly = "com.account.zoom.yearly"
|
|
|
|
|
|
var displayName: String {
|
|
|
switch self {
|
|
|
- case .weekly: return "Premium Weekly"
|
|
|
- case .monthly: return "Premium Monthly"
|
|
|
- case .yearly: return "Premium Yearly"
|
|
|
- case .lifetime: return "Premium Lifetime"
|
|
|
+ case .monthly: return "AI for Zoom Monthly"
|
|
|
+ case .biyearly: return "AI for Zoom Bi Yearly"
|
|
|
+ case .yearly: return "AI for Zoom Yearly"
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -639,8 +637,6 @@ class ViewController: NSViewController {
|
|
|
private(set) var activeProductIDs = Set<String>()
|
|
|
|
|
|
var hasPremiumAccess: Bool { !activeProductIDs.isEmpty }
|
|
|
- var hasLifetimePremiumAccess: Bool { activeProductIDs.contains(PremiumPlan.lifetime.rawValue) }
|
|
|
-
|
|
|
private var transactionUpdatesTask: Task<Void, Never>?
|
|
|
var onEntitlementsChanged: ((Bool) -> Void)?
|
|
|
|
|
|
@@ -3051,7 +3047,7 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
@objc private func upgradeToProTapped() {
|
|
|
- if storeKitCoordinator.hasLifetimePremiumAccess {
|
|
|
+ if storeKitCoordinator.hasPremiumAccess {
|
|
|
openManageSubscriptions()
|
|
|
} else {
|
|
|
showPaywall()
|
|
|
@@ -5536,12 +5532,11 @@ class ViewController: NSViewController {
|
|
|
@MainActor
|
|
|
private func updatePremiumButtons() {
|
|
|
let isPremium = storeKitCoordinator.hasPremiumAccess
|
|
|
- let hasLifetimePremium = storeKitCoordinator.hasLifetimePremiumAccess
|
|
|
settingsUpgradeButton?.title = ""
|
|
|
- settingsUpgradeTitleLabel?.stringValue = hasLifetimePremium ? "Premium Lifetime" : "Upgrade"
|
|
|
- settingsUpgradeButton?.isHidden = hasLifetimePremium
|
|
|
- settingsUpgradeButton?.isEnabled = hasLifetimePremium == false
|
|
|
- settingsUpgradeButton?.alphaValue = hasLifetimePremium ? 0.6 : 1.0
|
|
|
+ settingsUpgradeTitleLabel?.stringValue = isPremium ? "Premium Active" : "Upgrade"
|
|
|
+ settingsUpgradeButton?.isHidden = false
|
|
|
+ settingsUpgradeButton?.isEnabled = true
|
|
|
+ settingsUpgradeButton?.alphaValue = 1.0
|
|
|
settingsNotificationsBlock?.isHidden = isPremium == false
|
|
|
updatePremiumLockedSections()
|
|
|
if isPremium == false, isUserLoggedIn() {
|
|
|
@@ -5778,15 +5773,14 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
@objc private func settingsUpgradePremiumTapped() {
|
|
|
- guard storeKitCoordinator.hasLifetimePremiumAccess == false else { return }
|
|
|
showPaywall()
|
|
|
}
|
|
|
|
|
|
// MARK: - Paywall (ported from meetings_app)
|
|
|
|
|
|
private func showPaywall() {
|
|
|
- if storeKitCoordinator.hasPremiumAccess && storeKitCoordinator.hasLifetimePremiumAccess == false {
|
|
|
- selectedPremiumPlan = .lifetime
|
|
|
+ if storeKitCoordinator.hasPremiumAccess {
|
|
|
+ selectedPremiumPlan = .yearly
|
|
|
}
|
|
|
if let existing = paywallOverlayView {
|
|
|
refreshPaywallStoreUI()
|
|
|
@@ -6040,42 +6034,33 @@ class ViewController: NSViewController {
|
|
|
bodyStack.addArrangedSubview(planColumn)
|
|
|
planColumn.widthAnchor.constraint(equalTo: bodyStack.widthAnchor).isActive = true
|
|
|
|
|
|
- let weeklyCard = paywallPlanCard(
|
|
|
- title: "Weekly",
|
|
|
- price: paywallDisplayPrice(for: .weekly),
|
|
|
- badge: "Basic",
|
|
|
- badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
- subtitle: paywallPlanSubtitle(for: .weekly),
|
|
|
- plan: .weekly,
|
|
|
- strikePrice: nil
|
|
|
- )
|
|
|
let monthlyCard = paywallPlanCard(
|
|
|
title: "Monthly",
|
|
|
price: paywallDisplayPrice(for: .monthly),
|
|
|
- badge: "Popular",
|
|
|
+ badge: "Starter",
|
|
|
badgeColor: NSColor(calibratedRed: 0.19, green: 0.82, blue: 0.39, alpha: 1),
|
|
|
subtitle: paywallPlanSubtitle(for: .monthly),
|
|
|
plan: .monthly,
|
|
|
strikePrice: nil
|
|
|
)
|
|
|
+ let biYearlyCard = paywallPlanCard(
|
|
|
+ title: "Bi Yearly",
|
|
|
+ price: paywallDisplayPrice(for: .biyearly),
|
|
|
+ badge: "Popular",
|
|
|
+ badgeColor: NSColor(calibratedRed: 0.19, green: 0.82, blue: 0.39, alpha: 1),
|
|
|
+ subtitle: paywallPlanSubtitle(for: .biyearly),
|
|
|
+ plan: .biyearly,
|
|
|
+ strikePrice: nil
|
|
|
+ )
|
|
|
let yearlyCard = paywallPlanCard(
|
|
|
title: "Yearly",
|
|
|
price: paywallDisplayPrice(for: .yearly),
|
|
|
- badge: "Save 67%",
|
|
|
+ badge: "3 Days Free",
|
|
|
badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
subtitle: paywallPlanSubtitle(for: .yearly),
|
|
|
plan: .yearly,
|
|
|
strikePrice: nil
|
|
|
)
|
|
|
- let lifetimeCard = paywallPlanCard(
|
|
|
- title: "Lifetime",
|
|
|
- price: paywallDisplayPrice(for: .lifetime),
|
|
|
- badge: "Best Value",
|
|
|
- badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
- subtitle: paywallPlanSubtitle(for: .lifetime),
|
|
|
- plan: .lifetime,
|
|
|
- strikePrice: nil
|
|
|
- )
|
|
|
|
|
|
let plansRowWide = NSStackView()
|
|
|
plansRowWide.translatesAutoresizingMaskIntoConstraints = false
|
|
|
@@ -6083,10 +6068,9 @@ class ViewController: NSViewController {
|
|
|
plansRowWide.spacing = 12
|
|
|
plansRowWide.alignment = .centerY
|
|
|
plansRowWide.distribution = .fillEqually
|
|
|
- plansRowWide.addArrangedSubview(weeklyCard)
|
|
|
plansRowWide.addArrangedSubview(monthlyCard)
|
|
|
+ plansRowWide.addArrangedSubview(biYearlyCard)
|
|
|
plansRowWide.addArrangedSubview(yearlyCard)
|
|
|
- plansRowWide.addArrangedSubview(lifetimeCard)
|
|
|
paywallPlansRowWide = plansRowWide
|
|
|
planColumn.addArrangedSubview(plansRowWide)
|
|
|
plansRowWide.widthAnchor.constraint(equalTo: planColumn.widthAnchor).isActive = true
|
|
|
@@ -6104,24 +6088,24 @@ class ViewController: NSViewController {
|
|
|
plansRow1.spacing = 12
|
|
|
plansRow1.alignment = .centerY
|
|
|
plansRow1.distribution = .fillEqually
|
|
|
- plansRow1.addArrangedSubview(paywallPlanCard(
|
|
|
- title: "Weekly",
|
|
|
- price: paywallDisplayPrice(for: .weekly),
|
|
|
- badge: "Basic Deal",
|
|
|
- badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
- subtitle: paywallPlanSubtitle(for: .weekly),
|
|
|
- plan: .weekly,
|
|
|
- strikePrice: nil
|
|
|
- ))
|
|
|
plansRow1.addArrangedSubview(paywallPlanCard(
|
|
|
title: "Monthly",
|
|
|
price: paywallDisplayPrice(for: .monthly),
|
|
|
- badge: "Popular",
|
|
|
+ badge: "Starter",
|
|
|
badgeColor: NSColor(calibratedRed: 0.19, green: 0.82, blue: 0.39, alpha: 1),
|
|
|
subtitle: paywallPlanSubtitle(for: .monthly),
|
|
|
plan: .monthly,
|
|
|
strikePrice: nil
|
|
|
))
|
|
|
+ plansRow1.addArrangedSubview(paywallPlanCard(
|
|
|
+ title: "Bi Yearly",
|
|
|
+ price: paywallDisplayPrice(for: .biyearly),
|
|
|
+ badge: "Popular",
|
|
|
+ badgeColor: NSColor(calibratedRed: 0.19, green: 0.82, blue: 0.39, alpha: 1),
|
|
|
+ subtitle: paywallPlanSubtitle(for: .biyearly),
|
|
|
+ plan: .biyearly,
|
|
|
+ strikePrice: nil
|
|
|
+ ))
|
|
|
|
|
|
let plansRow2 = NSStackView()
|
|
|
plansRow2.translatesAutoresizingMaskIntoConstraints = false
|
|
|
@@ -6132,21 +6116,12 @@ class ViewController: NSViewController {
|
|
|
plansRow2.addArrangedSubview(paywallPlanCard(
|
|
|
title: "Yearly",
|
|
|
price: paywallDisplayPrice(for: .yearly),
|
|
|
- badge: "Best Deal",
|
|
|
+ badge: "3 Days Free",
|
|
|
badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
subtitle: paywallPlanSubtitle(for: .yearly),
|
|
|
plan: .yearly,
|
|
|
strikePrice: nil
|
|
|
))
|
|
|
- plansRow2.addArrangedSubview(paywallPlanCard(
|
|
|
- title: "Lifetime",
|
|
|
- price: paywallDisplayPrice(for: .lifetime),
|
|
|
- badge: "Save 50%",
|
|
|
- badgeColor: NSColor(calibratedRed: 1.0, green: 0.60, blue: 0.20, alpha: 1),
|
|
|
- subtitle: paywallPlanSubtitle(for: .lifetime),
|
|
|
- plan: .lifetime,
|
|
|
- strikePrice: nil
|
|
|
- ))
|
|
|
|
|
|
plansGridNarrow.addArrangedSubview(plansRow1)
|
|
|
plansGridNarrow.addArrangedSubview(plansRow2)
|
|
|
@@ -6604,16 +6579,12 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
private func paywallOfferText(for plan: PremiumPlan) -> String {
|
|
|
- if storeKitCoordinator.hasLifetimePremiumAccess {
|
|
|
- return "Lifetime premium is active on this Apple ID."
|
|
|
- }
|
|
|
guard let product = storeKitCoordinator.productsByID[plan.rawValue] else {
|
|
|
let price = paywallDisplayPrice(for: plan)
|
|
|
switch plan {
|
|
|
- case .weekly: return "\(price)/week"
|
|
|
case .monthly: return "\(price)/month"
|
|
|
+ case .biyearly: return "\(price)/6 months"
|
|
|
case .yearly: return "\(price)/year"
|
|
|
- case .lifetime: return "\(price) one-time purchase"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6627,20 +6598,15 @@ class ViewController: NSViewController {
|
|
|
return "Free for \(trial), then \(product.displayPrice)"
|
|
|
}
|
|
|
|
|
|
- if plan == .lifetime {
|
|
|
- return "\(product.displayPrice) one-time purchase"
|
|
|
- }
|
|
|
-
|
|
|
if let renewal = paywallSubscriptionPeriodDescription(product.subscription?.subscriptionPeriod) {
|
|
|
return "\(product.displayPrice)/\(renewal)"
|
|
|
}
|
|
|
|
|
|
let fallbackPrice = paywallDisplayPrice(for: plan)
|
|
|
switch plan {
|
|
|
- case .weekly: return "\(fallbackPrice)/week"
|
|
|
case .monthly: return "\(fallbackPrice)/month"
|
|
|
+ case .biyearly: return "\(fallbackPrice)/6 months"
|
|
|
case .yearly: return "\(fallbackPrice)/year"
|
|
|
- case .lifetime: return "\(fallbackPrice) one-time purchase"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6655,14 +6621,11 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
private func paywallPlanSubtitle(for plan: PremiumPlan) -> String {
|
|
|
- if plan == .lifetime { return "One-time purchase" }
|
|
|
-
|
|
|
guard let product = storeKitCoordinator.productsByID[plan.rawValue] else {
|
|
|
switch plan {
|
|
|
- case .weekly: return "Billed weekly"
|
|
|
case .monthly: return "Billed monthly"
|
|
|
+ case .biyearly: return "Billed every 6 months"
|
|
|
case .yearly: return "Billed yearly"
|
|
|
- case .lifetime: return "One-time purchase"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6678,10 +6641,9 @@ class ViewController: NSViewController {
|
|
|
}
|
|
|
|
|
|
switch plan {
|
|
|
- case .weekly: return "Billed weekly"
|
|
|
case .monthly: return "Billed monthly"
|
|
|
+ case .biyearly: return "Billed every 6 months"
|
|
|
case .yearly: return "Billed yearly"
|
|
|
- case .lifetime: return "One-time purchase"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6722,10 +6684,9 @@ class ViewController: NSViewController {
|
|
|
return product.displayPrice
|
|
|
}
|
|
|
switch plan {
|
|
|
- case .weekly: return "3.99"
|
|
|
- case .monthly: return "7.99"
|
|
|
- case .yearly: return "24.99"
|
|
|
- case .lifetime: return "44.99"
|
|
|
+ case .monthly: return "3.99"
|
|
|
+ case .biyearly: return "15.99"
|
|
|
+ case .yearly: return "29.99"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -6778,8 +6739,6 @@ class ViewController: NSViewController {
|
|
|
paywallPurchaseTask?.cancel()
|
|
|
updatePaywallContinueState(isLoading: true)
|
|
|
let selectedPlan = selectedPremiumPlan
|
|
|
- let hadPremiumBeforePurchase = storeKitCoordinator.hasPremiumAccess
|
|
|
- let hadLifetimeBeforePurchase = storeKitCoordinator.hasLifetimePremiumAccess
|
|
|
paywallPurchaseTask = Task { [weak self] in
|
|
|
guard let self else { return }
|
|
|
if self.storeKitCoordinator.productsByID[selectedPlan.rawValue] == nil {
|
|
|
@@ -6798,14 +6757,7 @@ class ViewController: NSViewController {
|
|
|
UserDefaults.standard.set(false, forKey: self.ratingPromptShownKey)
|
|
|
self.schedulePremiumRatingPromptIfNeeded()
|
|
|
}
|
|
|
- if selectedPlan == .lifetime, hadLifetimeBeforePurchase == false, hadPremiumBeforePurchase {
|
|
|
- self.showSimpleAlert(
|
|
|
- title: "Lifetime Activated",
|
|
|
- message: "Lifetime premium is now active. If you previously subscribed (weekly/monthly/yearly), please cancel that subscription in your Apple ID subscriptions to avoid future renewals."
|
|
|
- )
|
|
|
- } else {
|
|
|
- self.showSimpleAlert(title: "Purchase Complete", message: "Premium has been unlocked successfully.")
|
|
|
- }
|
|
|
+ self.showSimpleAlert(title: "Purchase Complete", message: "Premium has been unlocked successfully.")
|
|
|
self.hidePaywall()
|
|
|
if self.storeKitCoordinator.hasPremiumAccess {
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) { [weak self] in
|
|
|
@@ -6835,11 +6787,7 @@ class ViewController: NSViewController {
|
|
|
paywallContinueButton?.alphaValue = 0.75
|
|
|
return
|
|
|
}
|
|
|
- if storeKitCoordinator.hasLifetimePremiumAccess {
|
|
|
- paywallContinueEnabled = false
|
|
|
- paywallContinueLabel?.stringValue = "Lifetime Premium Active"
|
|
|
- paywallContinueButton?.alphaValue = 0.75
|
|
|
- } else if storeKitCoordinator.productsByID[selectedPremiumPlan.rawValue] == nil {
|
|
|
+ if storeKitCoordinator.productsByID[selectedPremiumPlan.rawValue] == nil {
|
|
|
paywallContinueEnabled = false
|
|
|
paywallContinueLabel?.stringValue = "Store Unavailable"
|
|
|
paywallContinueButton?.alphaValue = 0.75
|