|
@@ -45,12 +45,12 @@ final class StoreManager {
|
|
|
private(set) var purchaseError: PurchaseError?
|
|
private(set) var purchaseError: PurchaseError?
|
|
|
|
|
|
|
|
var isPro: Bool { isPremium }
|
|
var isPro: Bool { isPremium }
|
|
|
- var hasActiveSubscription: Bool { activePremiumPlan == .monthly || activePremiumPlan == .yearly }
|
|
|
|
|
- var hasLifetimeAccess: Bool { activePremiumPlan == .lifetime }
|
|
|
|
|
|
|
+ var hasActiveSubscription: Bool { activePremiumPlan?.isSubscription == true }
|
|
|
|
|
+ var hasLifetimeAccess: Bool { activePremiumPlan?.isLifetime == true }
|
|
|
var premiumAccessKind: PremiumAccessKind {
|
|
var premiumAccessKind: PremiumAccessKind {
|
|
|
- switch activePremiumPlan {
|
|
|
|
|
|
|
+ switch activePremiumPlan?.kind {
|
|
|
case .lifetime: .lifetime
|
|
case .lifetime: .lifetime
|
|
|
- case .monthly, .yearly: .subscription
|
|
|
|
|
|
|
+ case .weekly, .monthly, .yearly: .subscription
|
|
|
case nil: .none
|
|
case nil: .none
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -103,9 +103,9 @@ final class StoreManager {
|
|
|
let migratedPlan: String?
|
|
let migratedPlan: String?
|
|
|
switch legacyKind {
|
|
switch legacyKind {
|
|
|
case PremiumAccessKind.lifetime.rawValue:
|
|
case PremiumAccessKind.lifetime.rawValue:
|
|
|
- migratedPlan = PaywallPlan.lifetime.rawValue
|
|
|
|
|
|
|
+ migratedPlan = StoreKitCatalog.shared.productID(for: .lifetime)
|
|
|
case PremiumAccessKind.subscription.rawValue:
|
|
case PremiumAccessKind.subscription.rawValue:
|
|
|
- migratedPlan = PaywallPlan.yearly.rawValue
|
|
|
|
|
|
|
+ migratedPlan = StoreKitCatalog.shared.productID(for: .yearly)
|
|
|
default:
|
|
default:
|
|
|
migratedPlan = nil
|
|
migratedPlan = nil
|
|
|
}
|
|
}
|
|
@@ -118,23 +118,23 @@ final class StoreManager {
|
|
|
private func restoredCachedPremiumPlan() -> PaywallPlan? {
|
|
private func restoredCachedPremiumPlan() -> PaywallPlan? {
|
|
|
guard UserDefaults.standard.bool(forKey: Self.cachedPremiumKey) else { return nil }
|
|
guard UserDefaults.standard.bool(forKey: Self.cachedPremiumKey) else { return nil }
|
|
|
|
|
|
|
|
- if let raw = UserDefaults.standard.string(forKey: Self.cachedPremiumPlanKey),
|
|
|
|
|
- let plan = PaywallPlan(rawValue: raw) {
|
|
|
|
|
|
|
+ if let stored = UserDefaults.standard.string(forKey: Self.cachedPremiumPlanKey),
|
|
|
|
|
+ let plan = PaywallPlan.fromStoredValue(stored) {
|
|
|
return plan
|
|
return plan
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if let legacyKind = UserDefaults.standard.string(forKey: "StoreManager.cachedPremiumAccessKind") {
|
|
if let legacyKind = UserDefaults.standard.string(forKey: "StoreManager.cachedPremiumAccessKind") {
|
|
|
switch legacyKind {
|
|
switch legacyKind {
|
|
|
case PremiumAccessKind.lifetime.rawValue:
|
|
case PremiumAccessKind.lifetime.rawValue:
|
|
|
- return .lifetime
|
|
|
|
|
|
|
+ return StoreKitCatalog.shared.productID(for: .lifetime).map(PaywallPlan.init(productID:))
|
|
|
case PremiumAccessKind.subscription.rawValue:
|
|
case PremiumAccessKind.subscription.rawValue:
|
|
|
- return .yearly
|
|
|
|
|
|
|
+ return StoreKitCatalog.shared.productID(for: .yearly).map(PaywallPlan.init(productID:))
|
|
|
default:
|
|
default:
|
|
|
break
|
|
break
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- return .yearly
|
|
|
|
|
|
|
+ return StoreKitCatalog.shared.productID(for: .yearly).map(PaywallPlan.init(productID:))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
func start() {
|
|
func start() {
|
|
@@ -418,7 +418,7 @@ final class StoreManager {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if resolvedPlan == nil || resolvedPlan != .lifetime {
|
|
|
|
|
|
|
+ if resolvedPlan == nil || resolvedPlan?.isLifetime != true {
|
|
|
if let subscriptionPlan = await activeSubscriptionPlan() {
|
|
if let subscriptionPlan = await activeSubscriptionPlan() {
|
|
|
resolvedPlan = preferredPlan(resolvedPlan, subscriptionPlan)
|
|
resolvedPlan = preferredPlan(resolvedPlan, subscriptionPlan)
|
|
|
}
|
|
}
|
|
@@ -591,9 +591,9 @@ final class StoreManager {
|
|
|
private func applyPremiumStatus(plan: PaywallPlan?) {
|
|
private func applyPremiumStatus(plan: PaywallPlan?) {
|
|
|
let hasPremium = plan != nil
|
|
let hasPremium = plan != nil
|
|
|
let kind: PremiumAccessKind
|
|
let kind: PremiumAccessKind
|
|
|
- switch plan {
|
|
|
|
|
|
|
+ switch plan?.kind {
|
|
|
case .lifetime: kind = .lifetime
|
|
case .lifetime: kind = .lifetime
|
|
|
- case .monthly, .yearly: kind = .subscription
|
|
|
|
|
|
|
+ case .weekly, .monthly, .yearly: kind = .subscription
|
|
|
case nil: kind = .none
|
|
case nil: kind = .none
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -605,7 +605,7 @@ final class StoreManager {
|
|
|
activePremiumPlan = plan
|
|
activePremiumPlan = plan
|
|
|
UserDefaults.standard.set(hasPremium, forKey: Self.cachedPremiumKey)
|
|
UserDefaults.standard.set(hasPremium, forKey: Self.cachedPremiumKey)
|
|
|
if let plan {
|
|
if let plan {
|
|
|
- UserDefaults.standard.set(plan.rawValue, forKey: Self.cachedPremiumPlanKey)
|
|
|
|
|
|
|
+ UserDefaults.standard.set(plan.productID, forKey: Self.cachedPremiumPlanKey)
|
|
|
} else {
|
|
} else {
|
|
|
UserDefaults.standard.removeObject(forKey: Self.cachedPremiumPlanKey)
|
|
UserDefaults.standard.removeObject(forKey: Self.cachedPremiumPlanKey)
|
|
|
}
|
|
}
|
|
@@ -631,20 +631,13 @@ final class StoreManager {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func preferredPlan(_ current: PaywallPlan?, _ candidate: PaywallPlan) -> PaywallPlan {
|
|
private func preferredPlan(_ current: PaywallPlan?, _ candidate: PaywallPlan) -> PaywallPlan {
|
|
|
- if current == .lifetime || candidate == .lifetime {
|
|
|
|
|
- return .lifetime
|
|
|
|
|
- }
|
|
|
|
|
- if current == .yearly || candidate == .yearly {
|
|
|
|
|
- return .yearly
|
|
|
|
|
- }
|
|
|
|
|
- if current == .monthly || candidate == .monthly {
|
|
|
|
|
- return .monthly
|
|
|
|
|
- }
|
|
|
|
|
- return candidate
|
|
|
|
|
|
|
+ StoreKitCatalog.shared.preferredPlan(current, candidate)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func activeLifetimePlan() async -> PaywallPlan? {
|
|
private func activeLifetimePlan() async -> PaywallPlan? {
|
|
|
- let lifetimeProductID = PaywallPlan.lifetime.productID
|
|
|
|
|
|
|
+ guard let lifetimeProductID = StoreKitCatalog.shared.productID(for: .lifetime) else {
|
|
|
|
|
+ return nil
|
|
|
|
|
+ }
|
|
|
guard let result = await Transaction.latest(for: lifetimeProductID) else {
|
|
guard let result = await Transaction.latest(for: lifetimeProductID) else {
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
@@ -657,7 +650,7 @@ final class StoreManager {
|
|
|
|
|
|
|
|
for await result in Transaction.currentEntitlements {
|
|
for await result in Transaction.currentEntitlements {
|
|
|
guard case .verified(let transaction) = result else { continue }
|
|
guard case .verified(let transaction) = result else { continue }
|
|
|
- guard let plan = planGrantingPremium(from: transaction), plan != .lifetime else { continue }
|
|
|
|
|
|
|
+ guard let plan = planGrantingPremium(from: transaction), !plan.isLifetime else { continue }
|
|
|
resolvedPlan = preferredPlan(resolvedPlan, plan)
|
|
resolvedPlan = preferredPlan(resolvedPlan, plan)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -665,8 +658,7 @@ final class StoreManager {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private func activePlanFromSubscriptionStatus() async -> PaywallPlan? {
|
|
private func activePlanFromSubscriptionStatus() async -> PaywallPlan? {
|
|
|
- let subscriptionPlans = [PaywallPlan.monthly, .yearly]
|
|
|
|
|
- for plan in subscriptionPlans {
|
|
|
|
|
|
|
+ for plan in StoreKitCatalog.shared.subscriptionPlans {
|
|
|
let productID = plan.productID
|
|
let productID = plan.productID
|
|
|
let product: Product?
|
|
let product: Product?
|
|
|
if let cached = productsByID[productID] {
|
|
if let cached = productsByID[productID] {
|