UnitsConfigurationView.swift 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // LoopFollow
  2. // UnitsConfigurationView.swift
  3. import SwiftUI
  4. /// Reusable view for configuring units and metrics.
  5. /// Can be embedded in Forms or used standalone during onboarding.
  6. struct UnitsConfigurationView: View {
  7. @State private var rangeMode = UnitSettingsStore.shared.timeInRangeMode
  8. @State private var glucoseUnit = UnitSettingsStore.shared.glucoseUnit
  9. @State private var lowValue = Storage.shared.lowLine.value
  10. @State private var highValue = Storage.shared.highLine.value
  11. var body: some View {
  12. Group {
  13. Section("Glucose") {
  14. Picker("Glucose Unit", selection: $glucoseUnit) {
  15. Text("mg/dL").tag(GlucoseDisplayUnit.mgdL)
  16. Text("mmol/L").tag(GlucoseDisplayUnit.mmolL)
  17. }
  18. .pickerStyle(.segmented)
  19. .onChange(of: glucoseUnit) { newValue in
  20. UnitSettingsStore.shared.glucoseUnit = newValue
  21. }
  22. }
  23. Section("Range") {
  24. Picker("Range Mode", selection: $rangeMode) {
  25. Text("TIR").tag(TimeInRangeDisplayMode.tir)
  26. Text("TITR").tag(TimeInRangeDisplayMode.titr)
  27. Text("Custom").tag(TimeInRangeDisplayMode.custom)
  28. }
  29. .pickerStyle(.segmented)
  30. .onChange(of: rangeMode) { newValue in
  31. UnitSettingsStore.shared.timeInRangeMode = newValue
  32. Observable.shared.chartSettingsChanged.value = true
  33. }
  34. if rangeMode == .custom {
  35. BGPicker(
  36. title: "Low",
  37. range: 40 ... 120,
  38. value: $lowValue
  39. )
  40. .id(glucoseUnit)
  41. .onChange(of: lowValue) { newValue in
  42. Storage.shared.lowLine.value = newValue
  43. Observable.shared.chartSettingsChanged.value = true
  44. }
  45. BGPicker(
  46. title: "High",
  47. range: 120 ... 400,
  48. value: $highValue
  49. )
  50. .id(glucoseUnit)
  51. .onChange(of: highValue) { newValue in
  52. Storage.shared.highLine.value = newValue
  53. Observable.shared.chartSettingsChanged.value = true
  54. }
  55. }
  56. }
  57. Section("Glycemic Metrics") {
  58. Picker("Metric", selection: Binding(
  59. get: { UnitSettingsStore.shared.glycemicMetricMode },
  60. set: { UnitSettingsStore.shared.glycemicMetricMode = $0 }
  61. )) {
  62. Text("eHbA1c").tag(GlycemicMetricMode.ehba1c)
  63. Text("GMI").tag(GlycemicMetricMode.gmi)
  64. }
  65. .pickerStyle(.segmented)
  66. Picker("Output Unit", selection: Binding(
  67. get: { UnitSettingsStore.shared.glycemicOutputUnit },
  68. set: { UnitSettingsStore.shared.glycemicOutputUnit = $0 }
  69. )) {
  70. Text("%").tag(GlycemicOutputUnit.percent)
  71. Text("mmol/mol").tag(GlycemicOutputUnit.mmolMol)
  72. }
  73. .pickerStyle(.segmented)
  74. }
  75. Section("Variability") {
  76. Picker("Metric", selection: Binding(
  77. get: { UnitSettingsStore.shared.variabilityMetricMode },
  78. set: { UnitSettingsStore.shared.variabilityMetricMode = $0 }
  79. )) {
  80. Text("Std Dev").tag(VariabilityMetricMode.stdDeviation)
  81. Text("CV").tag(VariabilityMetricMode.cv)
  82. }
  83. .pickerStyle(.segmented)
  84. }
  85. }
  86. }
  87. }
  88. /// Standalone page for units configuration during onboarding.
  89. /// Shows a checkmark button in the toolbar to complete setup.
  90. struct UnitsOnboardingView: View {
  91. let onComplete: () -> Void
  92. var body: some View {
  93. Form {
  94. UnitsConfigurationView()
  95. }
  96. .navigationTitle("Set Up Units")
  97. .navigationBarTitleDisplayMode(.inline)
  98. .toolbar {
  99. ToolbarItem(placement: .navigationBarTrailing) {
  100. Button(action: {
  101. Storage.shared.hasConfiguredUnits.value = true
  102. onComplete()
  103. }) {
  104. Image(systemName: "checkmark")
  105. .fontWeight(.semibold)
  106. }
  107. }
  108. }
  109. }
  110. }