initial version
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user