NotificationsStepView.swift 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // LoopFollow
  2. // NotificationsStepView.swift
  3. import SwiftUI
  4. /// A short context screen ahead of the system notification prompt, following
  5. /// Apple's pre-alert guidance. The system prompt is triggered from here — before
  6. /// the final screen — so it never appears on top of "You're all set".
  7. struct NotificationsStepView: View {
  8. @ObservedObject var viewModel: OnboardingViewModel
  9. @State private var requesting = false
  10. var body: some View {
  11. VStack(spacing: 0) {
  12. VStack(alignment: .leading, spacing: 20) {
  13. Image(systemName: "bell.badge.fill")
  14. .font(.system(size: 44, weight: .semibold))
  15. .foregroundStyle(Color.accentColor)
  16. Text("Stay informed")
  17. .font(.title2.weight(.bold))
  18. Text("LoopFollow uses notifications to deliver your alarms — like low or high glucose, or a missed reading. Without them, alarms can't reach you when the app is in the background.")
  19. .font(.body)
  20. .foregroundColor(.secondary)
  21. .multilineTextAlignment(.leading)
  22. Text("We'll ask iOS for permission next. You can change this any time in the Settings app.")
  23. .font(.subheadline)
  24. .foregroundColor(.secondary)
  25. .multilineTextAlignment(.leading)
  26. }
  27. .frame(maxWidth: .infinity, alignment: .leading)
  28. .padding(.horizontal)
  29. .padding(.top, 8)
  30. Spacer()
  31. VStack(spacing: 12) {
  32. Button {
  33. guard !requesting else { return }
  34. requesting = true
  35. NotificationAuthorization.requestIfNeeded {
  36. viewModel.advance()
  37. }
  38. } label: {
  39. Text("Enable Notifications")
  40. .font(.body.weight(.semibold))
  41. .frame(maxWidth: .infinity)
  42. .padding(.vertical, 4)
  43. }
  44. .buttonStyle(.borderedProminent)
  45. .disabled(requesting)
  46. Button { viewModel.advance() } label: {
  47. Text("Not now")
  48. .font(.body.weight(.medium))
  49. }
  50. .disabled(requesting)
  51. }
  52. .padding(.horizontal, 24)
  53. .padding(.bottom, 24)
  54. }
  55. .frame(maxWidth: .infinity, maxHeight: .infinity)
  56. }
  57. }