AddTempTargetRootView.swift 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import SwiftUI
  2. import Swinject
  3. extension AddTempTarget {
  4. struct RootView: BaseView {
  5. let resolver: Resolver
  6. @StateObject var state = StateModel()
  7. @State private var isPromtPresented = false
  8. @State private var isRemoveAlertPresented = false
  9. @State private var removeAlert: Alert?
  10. @State private var isEditing = false
  11. private var formatter: NumberFormatter {
  12. let formatter = NumberFormatter()
  13. formatter.numberStyle = .decimal
  14. formatter.maximumFractionDigits = 1
  15. return formatter
  16. }
  17. var body: some View {
  18. Form {
  19. if !state.presets.isEmpty {
  20. Section(header: Text("Presets")) {
  21. ForEach(state.presets) { preset in
  22. presetView(for: preset)
  23. }
  24. }
  25. }
  26. Section(
  27. header: Text("Basal Insulin and Sensitivity ratio"),
  28. footer: Text(
  29. "A lower 'Half Basal Target' setting will lower the basal and raise the ISF earlier (at a lower target glucose)"
  30. )
  31. ) {
  32. VStack {
  33. Slider(
  34. value: $state.percentage,
  35. in: 15 ...
  36. Double(state.maxValue * 100),
  37. step: 1,
  38. onEditingChanged: { editing in
  39. isEditing = editing
  40. }
  41. )
  42. Text("\(state.percentage.formatted(.number)) %")
  43. .foregroundColor(isEditing ? .orange : .blue)
  44. .font(.largeTitle)
  45. Divider()
  46. Text(
  47. "Target" +
  48. (
  49. state
  50. .units == .mmolL ?
  51. ": \((Decimal(Double(state.halfBasal - 100) + 40 * (state.percentage / 100)) / (Decimal(state.percentage) / 100)).asMmolL.formatted(.number)) mmol/L" :
  52. ": \((Decimal(Double(state.halfBasal - 100) + 40 * (state.percentage / 100)) / (Decimal(state.percentage) / 100)).formatted(.number)) mg/dl"
  53. )
  54. ).foregroundColor(.secondary).italic()
  55. }
  56. }
  57. Section {
  58. HStack {
  59. Text("Duration")
  60. Spacer()
  61. DecimalTextField("0", value: $state.duration, formatter: formatter, cleanInput: true)
  62. Text("minutes").foregroundColor(.secondary)
  63. }
  64. DatePicker("Date", selection: $state.date)
  65. Button { isPromtPresented = true }
  66. label: { Text("Save as preset") }
  67. }
  68. Section {
  69. Button { state.enact() }
  70. label: { Text("Enact") }
  71. Button { state.cancel() }
  72. label: { Text("Cancel Temp Target") }
  73. }
  74. }
  75. .popover(isPresented: $isPromtPresented) {
  76. Form {
  77. Section(header: Text("Enter preset name")) {
  78. TextField("Name", text: $state.newPresetName)
  79. Button {
  80. state.save()
  81. isPromtPresented = false
  82. }
  83. label: { Text("Save") }
  84. Button { isPromtPresented = false }
  85. label: { Text("Cancel") }
  86. }
  87. }
  88. }
  89. .onAppear(perform: configureView)
  90. .navigationTitle("Enact Temp Target")
  91. .navigationBarTitleDisplayMode(.automatic)
  92. .navigationBarItems(leading: Button("Close", action: state.hideModal))
  93. }
  94. private func presetView(for preset: TempTarget) -> some View {
  95. var low = preset.targetBottom
  96. var high = preset.targetTop
  97. if state.units == .mmolL {
  98. low = low?.asMmolL
  99. high = high?.asMmolL
  100. }
  101. return HStack {
  102. VStack {
  103. HStack {
  104. Text(preset.displayName)
  105. Spacer()
  106. }
  107. HStack(spacing: 2) {
  108. Text(
  109. "\(formatter.string(from: (low ?? 0) as NSNumber)!) - \(formatter.string(from: (high ?? 0) as NSNumber)!)"
  110. )
  111. .foregroundColor(.secondary)
  112. .font(.caption)
  113. Text(state.units.rawValue)
  114. .foregroundColor(.secondary)
  115. .font(.caption)
  116. Text("for")
  117. .foregroundColor(.secondary)
  118. .font(.caption)
  119. Text("\(formatter.string(from: preset.duration as NSNumber)!)")
  120. .foregroundColor(.secondary)
  121. .font(.caption)
  122. Text("min")
  123. .foregroundColor(.secondary)
  124. .font(.caption)
  125. Spacer()
  126. }.padding(.top, 2)
  127. }
  128. .contentShape(Rectangle())
  129. .onTapGesture {
  130. state.enactPreset(id: preset.id)
  131. }
  132. Image(systemName: "xmark.circle").foregroundColor(.secondary)
  133. .contentShape(Rectangle())
  134. .padding(.vertical)
  135. .onTapGesture {
  136. removeAlert = Alert(
  137. title: Text("Are you sure?"),
  138. message: Text("Delete preset \"\(preset.displayName)\""),
  139. primaryButton: .destructive(Text("Delete"), action: { state.removePreset(id: preset.id) }),
  140. secondaryButton: .cancel()
  141. )
  142. isRemoveAlertPresented = true
  143. }
  144. .alert(isPresented: $isRemoveAlertPresented) {
  145. removeAlert!
  146. }
  147. }
  148. }
  149. }
  150. }