OverviewStepView.swift 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // LoopFollow
  2. // OverviewStepView.swift
  3. import SwiftUI
  4. /// A quick map of what the rest of setup covers, so the user knows what to
  5. /// expect. The list reflects the phases that will actually run — a returning
  6. /// user who's already connected won't see "Connect your data" — and collapses to
  7. /// a short "you're all set" when there's nothing left to configure.
  8. struct OverviewStepView: View {
  9. @ObservedObject var onboarding: OnboardingViewModel
  10. private struct Item: Identifiable {
  11. let id = UUID()
  12. let icon: String
  13. let title: String
  14. let detail: String
  15. }
  16. /// The overview rows, derived from the phases that will actually run.
  17. private var items: [Item] {
  18. let steps = onboarding.activeSteps
  19. var result: [Item] = []
  20. if steps.contains(.connect) {
  21. result.append(Item(icon: "antenna.radiowaves.left.and.right",
  22. title: "Connect your data",
  23. detail: "Link a Nightscout site or a Dexcom Share account."))
  24. }
  25. if steps.contains(.units) {
  26. result.append(Item(icon: "ruler",
  27. title: "Units & metrics",
  28. detail: "Choose how glucose and statistics are shown."))
  29. }
  30. if steps.contains(.alarms) {
  31. result.append(Item(icon: "bell.badge.fill",
  32. title: "Recommended alarms",
  33. detail: "Turn on a few useful alarms with sensible defaults."))
  34. }
  35. if steps.contains(.tabOrder) {
  36. result.append(Item(icon: "square.grid.2x2",
  37. title: "Finish up",
  38. detail: "Arrange your tabs and set notification preferences."))
  39. }
  40. return result
  41. }
  42. var body: some View {
  43. VStack(spacing: 0) {
  44. if onboarding.hasNothingToSetUp {
  45. allSet
  46. } else {
  47. checklist
  48. }
  49. footer
  50. }
  51. }
  52. // MARK: - Content
  53. private var checklist: some View {
  54. ScrollView {
  55. VStack(alignment: .leading, spacing: 24) {
  56. OnboardingStepHeader(
  57. systemImage: "list.bullet.rectangle",
  58. title: "Here's what we'll do",
  59. subtitle: "A quick, straightforward setup — about 5 minutes. You can change anything later in Settings."
  60. )
  61. .padding(.horizontal)
  62. VStack(spacing: 14) {
  63. ForEach(items) { item in
  64. HStack(alignment: .top, spacing: 14) {
  65. Image(systemName: item.icon)
  66. .font(.title3)
  67. .foregroundStyle(Color.accentColor)
  68. .frame(width: 32)
  69. VStack(alignment: .leading, spacing: 4) {
  70. Text(item.title)
  71. .font(.headline)
  72. Text(item.detail)
  73. .font(.subheadline)
  74. .foregroundColor(.secondary)
  75. .multilineTextAlignment(.leading)
  76. }
  77. Spacer(minLength: 0)
  78. }
  79. .frame(maxWidth: .infinity, alignment: .leading)
  80. .padding()
  81. .background(
  82. RoundedRectangle(cornerRadius: 14, style: .continuous)
  83. .fill(Color(.secondarySystemGroupedBackground))
  84. )
  85. }
  86. }
  87. .padding(.horizontal)
  88. }
  89. .padding(.bottom, 24)
  90. }
  91. }
  92. private var allSet: some View {
  93. ScrollView {
  94. OnboardingStepHeader(
  95. systemImage: "checkmark.circle",
  96. title: "You're all set",
  97. subtitle: "Your data source is connected and your alarms are in place — there's nothing to set up here. You can fine-tune anything later in Settings."
  98. )
  99. .padding(.horizontal)
  100. .padding(.top, 24)
  101. }
  102. }
  103. // MARK: - Footer
  104. private var footer: some View {
  105. OnboardingNavFooter(
  106. continueTitle: onboarding.hasNothingToSetUp ? "Done" : "Continue",
  107. continueEnabled: true,
  108. showBack: onboarding.canGoBack,
  109. onBack: { onboarding.goBack() },
  110. onContinue: {
  111. if onboarding.hasNothingToSetUp {
  112. onboarding.finish()
  113. } else {
  114. onboarding.advance()
  115. }
  116. }
  117. )
  118. }
  119. }