AutotuneConfigRootView.swift 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import SwiftUI
  2. import Swinject
  3. extension AutotuneConfig {
  4. struct RootView: BaseView {
  5. let resolver: Resolver
  6. @StateObject var state = StateModel()
  7. @State private var shouldDisplayHint: Bool = false
  8. @State var hintDetent = PresentationDetent.large
  9. @State var selectedVerboseHint: String?
  10. @State var hintLabel: String?
  11. @State private var decimalPlaceholder: Decimal = 0.0
  12. @State private var booleanPlaceholder: Bool = false
  13. @State var replaceAlert = false
  14. @Environment(\.colorScheme) var colorScheme
  15. @Environment(AppState.self) var appState
  16. private var isfFormatter: NumberFormatter {
  17. let formatter = NumberFormatter()
  18. formatter.numberStyle = .decimal
  19. formatter.maximumFractionDigits = 2
  20. return formatter
  21. }
  22. private var rateFormatter: NumberFormatter {
  23. let formatter = NumberFormatter()
  24. formatter.numberStyle = .decimal
  25. formatter.maximumFractionDigits = 2
  26. return formatter
  27. }
  28. private var dateFormatter: DateFormatter {
  29. let formatter = DateFormatter()
  30. formatter.dateStyle = .medium
  31. formatter.timeStyle = .short
  32. return formatter
  33. }
  34. var body: some View {
  35. Form {
  36. SettingInputSection(
  37. decimalValue: $decimalPlaceholder,
  38. booleanValue: $state.useAutotune,
  39. shouldDisplayHint: $shouldDisplayHint,
  40. selectedVerboseHint: Binding(
  41. get: { selectedVerboseHint },
  42. set: {
  43. selectedVerboseHint = $0
  44. hintLabel = "Use Autotune"
  45. }
  46. ),
  47. units: state.units,
  48. type: .boolean,
  49. label: "Use Autotune",
  50. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  51. verboseHint: "Autotune… bla bla bla",
  52. headerText: "Data-driven Adjustments"
  53. )
  54. if state.useAutotune {
  55. SettingInputSection(
  56. decimalValue: $decimalPlaceholder,
  57. booleanValue: $state.onlyAutotuneBasals,
  58. shouldDisplayHint: $shouldDisplayHint,
  59. selectedVerboseHint: Binding(
  60. get: { selectedVerboseHint },
  61. set: {
  62. selectedVerboseHint = $0
  63. hintLabel = "Only Autotune Basal Insulin"
  64. }
  65. ),
  66. units: state.units,
  67. type: .boolean,
  68. label: "Only Autotune Basal Insulin",
  69. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  70. verboseHint: "Only Autotune Basal Insulin… bla bla bla"
  71. )
  72. }
  73. Section(
  74. header: HStack {
  75. Text("Last run")
  76. Spacer()
  77. Text(dateFormatter.string(from: state.publishedDate))
  78. },
  79. content: {
  80. Button {
  81. state.run()
  82. } label: {
  83. Text("Run now")
  84. }
  85. .frame(maxWidth: .infinity, alignment: .center)
  86. .listRowBackground(Color(.systemBlue))
  87. .tint(.white)
  88. }
  89. )
  90. if let autotune = state.autotune {
  91. if !state.onlyAutotuneBasals {
  92. Section {
  93. HStack {
  94. Text("Carb ratio")
  95. Spacer()
  96. Text(isfFormatter.string(from: autotune.carbRatio as NSNumber) ?? "0")
  97. Text("g/U").foregroundColor(.secondary)
  98. }
  99. HStack {
  100. Text("Sensitivity")
  101. Spacer()
  102. if state.units == .mmolL {
  103. Text(isfFormatter.string(from: autotune.sensitivity.asMmolL as NSNumber) ?? "0")
  104. } else {
  105. Text(isfFormatter.string(from: autotune.sensitivity as NSNumber) ?? "0")
  106. }
  107. Text(state.units.rawValue + "/U").foregroundColor(.secondary)
  108. }
  109. }
  110. .listRowBackground(Color.chart)
  111. }
  112. Section(header: Text("Basal profile")) {
  113. ForEach(0 ..< autotune.basalProfile.count, id: \.self) { index in
  114. HStack {
  115. Text(autotune.basalProfile[index].start).foregroundColor(.secondary)
  116. Spacer()
  117. Text(rateFormatter.string(from: autotune.basalProfile[index].rate as NSNumber) ?? "0")
  118. Text("U/hr").foregroundColor(.secondary)
  119. }
  120. }
  121. HStack {
  122. Text("Total")
  123. .bold()
  124. .foregroundColor(.primary)
  125. Spacer()
  126. Text(rateFormatter.string(from: autotune.basalProfile.reduce(0) { $0 + $1.rate } as NSNumber) ?? "0")
  127. .foregroundColor(.primary) +
  128. Text(" U/day")
  129. .foregroundColor(.secondary)
  130. }
  131. }
  132. .listRowBackground(Color.chart)
  133. Section {
  134. Button {
  135. Task {
  136. await state.delete()
  137. }
  138. } label: {
  139. Text("Delete Autotune Data")
  140. }
  141. .frame(maxWidth: .infinity, alignment: .center)
  142. .listRowBackground(Color(.loopRed))
  143. .tint(.white)
  144. }
  145. // Section {
  146. // Button {
  147. // replaceAlert = true
  148. // } label: {
  149. // Text("Save as Normal Basal Rates")
  150. // }
  151. // .frame(maxWidth: .infinity, alignment: .center)
  152. // .listRowBackground(Color(.systemGray4))
  153. // .tint(.white)
  154. // }
  155. }
  156. }
  157. .sheet(isPresented: $shouldDisplayHint) {
  158. SettingInputHintView(
  159. hintDetent: $hintDetent,
  160. shouldDisplayHint: $shouldDisplayHint,
  161. hintLabel: hintLabel ?? "",
  162. hintText: selectedVerboseHint ?? "",
  163. sheetTitle: "Help"
  164. )
  165. }
  166. .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme))
  167. .onAppear(perform: configureView)
  168. .navigationTitle("Autotune")
  169. .navigationBarTitleDisplayMode(.automatic)
  170. .alert(Text("Are you sure?"), isPresented: $replaceAlert) {
  171. Button("Yes", action: {
  172. state.replace()
  173. replaceAlert.toggle()
  174. })
  175. Button("No", action: { replaceAlert.toggle() })
  176. }
  177. }
  178. }
  179. }