UnitsStepView.swift 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // LoopFollow
  2. // UnitsStepView.swift
  3. import SwiftUI
  4. /// The units phase, split into two lighter pages so it doesn't feel heavy:
  5. /// 1. **Units** — the glucose display unit on its own.
  6. /// 2. **Statistics** — range mode and the glycemic/variability metrics LoopFollow
  7. /// shows.
  8. ///
  9. /// Both pages reuse `UnitsConfigurationView`, each rendering only its subset of
  10. /// sections. The phase reports its within-phase position through
  11. /// `phaseProgress` so the progress bar fills smoothly across the two pages.
  12. struct UnitsStepView: View {
  13. @ObservedObject var onboarding: OnboardingViewModel
  14. private enum Page: Int, CaseIterable { case units, statistics }
  15. @State private var page: Page = .units
  16. var body: some View {
  17. VStack(spacing: 0) {
  18. Form {
  19. switch page {
  20. case .units:
  21. header(
  22. systemImage: "ruler",
  23. title: "Units",
  24. subtitle: "Choose how glucose values are displayed. You can change this later in Settings."
  25. )
  26. UnitsConfigurationView(sections: .units)
  27. case .statistics:
  28. header(
  29. systemImage: "chart.bar.xaxis",
  30. title: "Statistics",
  31. subtitle: "Choose how LoopFollow's statistics are measured and displayed."
  32. )
  33. UnitsConfigurationView(sections: .statistics)
  34. }
  35. }
  36. footer
  37. }
  38. .onAppear { reportProgress() }
  39. .onChange(of: page) { _ in reportProgress() }
  40. }
  41. private func reportProgress() {
  42. onboarding.phaseProgress = .init(page: page.rawValue, count: Page.allCases.count)
  43. }
  44. private func header(systemImage: String, title: String, subtitle: String) -> some View {
  45. Section {
  46. EmptyView()
  47. } header: {
  48. OnboardingStepHeader(
  49. systemImage: systemImage,
  50. title: title,
  51. subtitle: subtitle
  52. )
  53. .textCase(nil)
  54. .padding(.bottom, 8)
  55. }
  56. .listRowInsets(EdgeInsets())
  57. .listRowBackground(Color.clear)
  58. }
  59. @ViewBuilder
  60. private var footer: some View {
  61. switch page {
  62. case .units:
  63. OnboardingNavFooter(
  64. continueEnabled: true,
  65. showBack: onboarding.canGoBack,
  66. onBack: { onboarding.goBack() },
  67. onContinue: { withAnimation(.easeInOut(duration: 0.25)) { page = .statistics } }
  68. )
  69. case .statistics:
  70. OnboardingNavFooter(
  71. continueEnabled: true,
  72. showBack: true,
  73. onBack: { withAnimation(.easeInOut(duration: 0.25)) { page = .units } },
  74. onContinue: { onboarding.advance() }
  75. )
  76. }
  77. }
  78. }