Settings, AppConfig & lifecycle

A ready-made settings hub, one place for configuration, and the two lifecycle "asks" — timed to a genuine high, never on launch.

AppConfig — one source of truth

Pass an AppConfig to LaunchGate. Settings sections auto-hide based on what you configure.

LaunchGate(config: .myApp,
           provider: PreviewPurchaseProvider(),
           appConfig: AppConfig(
             supportURL: URL(string: "https://delicious.works/support"),
             privacyURL: URL(string: "https://delicious.works/privacy"),
             feedbackEmail: "hello@delicious.works"
           )) {
  ContentView()
}

The settings hub

DeliciousKitSettingsView is a data-driven settings screen — Account and Purchases sections auto-hide when auth or IAP aren't configured. Inject your app's own sections via the trailing closure:

DeliciousKitSettingsView {
  Section("Preferences") {
    Toggle("Dark mode", isOn: $darkMode)
  }
}

Review prompts

ReviewPrompter requests a review at a genuine high — never on launch, never after an error. Record your meaningful events and let it choose the moment:

ReviewPrompter.shared.recordEvent()   // after a real win

What's New

Show a post-update sheet by passing a WhatsNewConfig:

LaunchGate(config: .myApp,
           provider: PreviewPurchaseProvider(),
           whatsNew: WhatsNewConfig(version: "1.2", items: [
             .init(icon: "star.fill", title: "New feature", description: "…")
           ])) {
  ContentView()
}

Both follow the same rule as permission prompts: earn it, time it to a high, and never nag. The timing philosophy lives in the Delicious Onboarding skill.