1.2.0: contextual notifications + in-onboarding auto-fill (aha moment)

- New "Week Ready" onboarding step: auto-fills the first week inline right
  after dish creation, then pitches the Sunday reminder with context before
  requesting OS notification permission (no more cold prompt on Home)
- Notifications section in Settings: weekly reminder toggle, deep-link to
  system settings when permission is denied
- NotificationService: remindersEnabled preference, requestPermission(),
  authorizationStatus(), cancelAllReminders()
- Post-onboarding premium prompt deferred to 2nd session (paywall was just
  shown as the final onboarding step — 2s-later alert was prompt fatigue)
- Back navigation blocked after onboarding commit to avoid duplicate dishes
- 10 new strings × 6 languages

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UtWT52pAE91D7mbDda1cAM
This commit is contained in:
alexandrev-tibco
2026-07-03 10:08:04 +02:00
parent 13ece5f2e7
commit 73c2039338
13 changed files with 415 additions and 49 deletions
+9 -1
View File
@@ -515,7 +515,8 @@ struct HomeView: View {
StatsView(weekPlans: weekPlans, allDishes: dishes, allTags: tags, language: settings.languageEnum.resolved())
}
.task {
await NotificationService.shared.requestPermissionIfNeeded()
// Permission is now requested contextually (onboarding Week Ready step or
// the Settings toggle) no cold OS prompt on first Home load.
let nextPlan = fetchWeekPlan(for: Date().startOfWeek().addingDays(7))
NotificationService.shared.schedulePlanningReminderIfNeeded(
nextWeekPlan: nextPlan,
@@ -986,6 +987,13 @@ struct HomeView: View {
let shouldShowPremiumPrompt = UserDefaults.standard.bool(forKey: OnboardingViewModel.pendingPremiumPromptKey)
guard shouldShowPremiumPrompt else { return }
// The paywall was just shown as the final onboarding step prompting again
// 2s later is prompt fatigue. Defer to the second session instead.
let sessionCountKey = "post_onboarding_session_count"
let sessions = UserDefaults.standard.integer(forKey: sessionCountKey) + 1
UserDefaults.standard.set(sessions, forKey: sessionCountKey)
guard sessions >= 2 else { return }
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
showPostOnboardingPremiumPrompt = true
}