import Foundation import CoreData /// Decides when to ask for an App Store rating: after a "positive moment" /// (a saved check-in), only once the habit is established (≥2 distinct months /// of snapshots) and at most once per app version. Apple additionally caps /// the system prompt at 3 displays per year, so over-calling is safe. /// /// Call sites own the actual prompt via SwiftUI's `\.requestReview` — this /// service only answers "should we ask now?" and records that we did. @MainActor enum ReviewRequestService { private static let lastVersionKey = "reviewRequest.lastVersion" /// Returns true at most once per app version, and only when the user has /// snapshots in 2+ distinct months (they've seen the app deliver value). /// Marks the version as asked when returning true. static func shouldRequestAfterCheckIn() -> Bool { guard distinctSnapshotMonths() >= 2 else { return false } let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String ?? "unknown" let defaults = UserDefaults.standard guard defaults.string(forKey: lastVersionKey) != version else { return false } defaults.set(version, forKey: lastVersionKey) return true } private static func distinctSnapshotMonths() -> Int { let request = NSFetchRequest(entityName: "Snapshot") guard let snapshots = try? CoreDataStack.shared.viewContext.fetch(request) else { return 0 } let calendar = Calendar.current let months = Set(snapshots.map { snapshot in calendar.dateComponents([.year, .month], from: snapshot.date) }) return months.count } }