InvestmentTrackerApp/PortfolioJournal/Utilities/FreemiumValidator.swift

195 lines
5.5 KiB
Swift

import Foundation
import Combine
enum FreemiumLimits {
static let maxSources = 5
static let maxHistoricalMonths = 12
}
class FreemiumValidator: ObservableObject {
private let iapService: IAPService
init(iapService: IAPService) {
self.iapService = iapService
}
// MARK: - Source Limits
var isPremium: Bool {
iapService.isPremium
}
func canAddSource(currentCount: Int) -> Bool {
if iapService.isPremium { return true }
return currentCount < FreemiumLimits.maxSources
}
func remainingSources(currentCount: Int) -> Int {
if iapService.isPremium { return Int.max }
return max(0, FreemiumLimits.maxSources - currentCount)
}
var sourceLimit: Int {
iapService.isPremium ? Int.max : FreemiumLimits.maxSources
}
var sourceLimitDescription: String {
if iapService.isPremium {
return "Unlimited"
}
return "\(FreemiumLimits.maxSources) sources"
}
// MARK: - Historical Data Limits
func filterSnapshots(_ snapshots: [Snapshot]) -> [Snapshot] {
if iapService.isPremium { return snapshots }
let cutoffDate = Calendar.current.date(
byAdding: .month,
value: -FreemiumLimits.maxHistoricalMonths,
to: Date()
) ?? Date()
return snapshots.filter { $0.date >= cutoffDate }
}
func isSnapshotAccessible(_ snapshot: Snapshot) -> Bool {
if iapService.isPremium { return true }
let cutoffDate = Calendar.current.date(
byAdding: .month,
value: -FreemiumLimits.maxHistoricalMonths,
to: Date()
) ?? Date()
return snapshot.date >= cutoffDate
}
var historicalLimit: Int {
iapService.isPremium ? Int.max : FreemiumLimits.maxHistoricalMonths
}
var historicalLimitDescription: String {
if iapService.isPremium {
return "Full history"
}
return "Last \(FreemiumLimits.maxHistoricalMonths) months"
}
// MARK: - Feature Access
func canExport() -> Bool {
return iapService.isPremium
}
func canViewPredictions() -> Bool {
return iapService.isPremium
}
func canViewAdvancedCharts() -> Bool {
return iapService.isPremium
}
func canAccessFeature(_ feature: PremiumFeature) -> Bool {
if iapService.isPremium { return true }
switch feature {
case .multipleAccounts:
return false
case .unlimitedSources:
return false
case .fullHistory:
return false
case .advancedCharts:
return false
case .predictions:
return false
case .export:
return false
case .noAds:
return false
}
}
// MARK: - Premium Features Enum
enum PremiumFeature: String, CaseIterable, Identifiable {
case multipleAccounts = "multiple_accounts"
case unlimitedSources = "unlimited_sources"
case fullHistory = "full_history"
case advancedCharts = "advanced_charts"
case predictions = "predictions"
case export = "export"
case noAds = "no_ads"
var id: String { rawValue }
var title: String {
switch self {
case .multipleAccounts: return "Multiple Accounts"
case .unlimitedSources: return "Unlimited Sources"
case .fullHistory: return "Full History"
case .advancedCharts: return "Advanced Charts"
case .predictions: return "Predictions"
case .export: return "Export Data"
case .noAds: return "No Ads"
}
}
var icon: String {
switch self {
case .multipleAccounts: return "person.2"
case .unlimitedSources: return "infinity"
case .fullHistory: return "clock.arrow.circlepath"
case .advancedCharts: return "chart.bar.xaxis"
case .predictions: return "wand.and.stars"
case .export: return "square.and.arrow.up"
case .noAds: return "xmark.circle"
}
}
var description: String {
switch self {
case .multipleAccounts:
return "Track separate portfolios for family or business"
case .unlimitedSources:
return "Track as many investment sources as you want"
case .fullHistory:
return "Access your complete investment history"
case .advancedCharts:
return "5 types of detailed analytics charts"
case .predictions:
return "AI-powered 12-month forecasts"
case .export:
return "Export to CSV and JSON formats"
case .noAds:
return "Ad-free experience forever"
}
}
}
// MARK: - Paywall Triggers
enum PaywallTrigger: String {
case sourceLimit = "source_limit"
case historyLimit = "history_limit"
case advancedCharts = "advanced_charts"
case predictions = "predictions"
case export = "export"
case settingsUpgrade = "settings_upgrade"
case manualTap = "manual_tap"
}
func shouldShowPaywall(for trigger: PaywallTrigger) -> Bool {
guard !iapService.isPremium else { return false }
switch trigger {
case .sourceLimit, .historyLimit, .advancedCharts, .predictions, .export:
return true
case .settingsUpgrade, .manualTap:
return true
}
}
}