import Foundation
import Encore
import Combine
import SuperwallKit
import RevenueCat
class EntitlementManager: NSObject, ObservableObject {
@Published var hasProAccess: Bool = false
private var cancellables = Set<AnyCancellable>()
private let revenueCatStatusSubject = CurrentValueSubject<Bool, Never>(false)
override init() {
super.init()
// 🔑 Set delegate so we get subscription updates
Purchases.shared.delegate = self
// Listen for RevenueCat events
setupRevenueCatListener()
// Combine IAP subscription status with Encore promotional rewards + Superwall
Publishers.CombineLatest3(
revenueCatStatusSubject.eraseToAnyPublisher(),
Superwall.shared.$subscriptionStatus,
Encore.shared.isActivePublisher(for: .freeTrial())
)
.map { revenuecatActive, superwallActive, encoreActive in
// User has pro access if:
// - They have any RevenueCat entitlements
// - OR they have an active Superwall subscription
// - OR they have an active Encore reward
return revenuecatActive || (superwallActive != .inactive) || encoreActive
}
.assign(to: \.hasProAccess, on: self)
.store(in: &cancellables)
}
private func setupRevenueCatListener() {
// Fetch initial CustomerInfo
Purchases.shared.getCustomerInfo { [weak self] customerInfo, error in
guard let self = self else { return }
if let customerInfo = customerInfo {
self.updateRevenueCatStatus(from: customerInfo)
} else if let error = error {
print("Error fetching CustomerInfo: \(error)")
}
}
}
private func updateRevenueCatStatus(from customerInfo: CustomerInfo) {
// Check for active entitlements
let hasActiveEntitlement = !customerInfo.entitlements.active.isEmpty
print("RevenueCat entitlements: \(customerInfo.entitlements.active.keys)")
revenueCatStatusSubject.send(hasActiveEntitlement)
}
}
// MARK: - PurchasesDelegate
extension EntitlementManager: PurchasesDelegate {
func purchases(_ purchases: Purchases, receivedUpdated customerInfo: CustomerInfo) {
print("RevenueCat CustomerInfo updated")
updateRevenueCatStatus(from: customerInfo)
}
}