1.0.1: add review funnel, trial onboarding, and app diagnostics

This commit is contained in:
alexandrev-tibco
2026-02-26 10:33:45 +01:00
parent c5c7e3d2e4
commit 9bdbf80e67
8 changed files with 253 additions and 27 deletions
+21 -17
View File
@@ -5,35 +5,39 @@ import StoreKit
final class ReviewPromptService {
static let shared = ReviewPromptService()
private let milestones = [1, 2, 4, 8]
private let minimumDaysBetweenPrompts: Double = 30
private let promptedMilestoneKey = "review_prompted_milestone"
private let lastPromptDateKey = "review_prompt_last_date"
private let reviewCompletedKey = "review_funnel_completed"
private let lastPromptedCompletedWeeksKey = "review_funnel_last_prompted_completed_weeks"
private let minimumCompletedWeeksToStart = 2
private let promptIntervalWeeks = 2
private init() {}
func considerPromptAfterWeekCompletion(completedWeeks: Int) {
guard let milestone = milestones.first(where: { completedWeeks >= $0 }) else { return }
let alreadyPrompted = UserDefaults.standard.integer(forKey: promptedMilestoneKey)
guard milestone > alreadyPrompted else { return }
guard canPromptNow() else { return }
func shouldShowFunnelAfterWeekCompletion(completedWeeks: Int) -> Bool {
guard !hasCompletedReviewFlow else { return false }
guard completedWeeks >= minimumCompletedWeeksToStart else { return false }
guard completedWeeks % promptIntervalWeeks == 0 else { return false }
requestReview()
UserDefaults.standard.set(milestone, forKey: promptedMilestoneKey)
UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: lastPromptDateKey)
let lastPrompted = UserDefaults.standard.integer(forKey: lastPromptedCompletedWeeksKey)
return completedWeeks > lastPrompted
}
func markFunnelShown(completedWeeks: Int) {
UserDefaults.standard.set(completedWeeks, forKey: lastPromptedCompletedWeeksKey)
}
func markReviewCompleted() {
UserDefaults.standard.set(true, forKey: reviewCompletedKey)
}
func requestFromSettings() {
requestReview()
}
private func canPromptNow() -> Bool {
let lastPrompt = UserDefaults.standard.double(forKey: lastPromptDateKey)
guard lastPrompt > 0 else { return true }
return Date().timeIntervalSince1970 - lastPrompt >= minimumDaysBetweenPrompts * 24 * 60 * 60
var hasCompletedReviewFlow: Bool {
UserDefaults.standard.bool(forKey: reviewCompletedKey)
}
private func requestReview() {
func requestReview() {
guard let scene = UIApplication.shared.connectedScenes
.compactMap({ $0 as? UIWindowScene })
.first(where: { $0.activationState == .foregroundActive }) else { return }