ISFEditorRootView.swift 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import SwiftUI
  2. extension ISFEditor {
  3. struct RootView: BaseView {
  4. @EnvironmentObject var viewModel: ViewModel<Provider>
  5. @State private var editMode = EditMode.inactive
  6. private var dateFormatter: DateFormatter {
  7. let formatter = DateFormatter()
  8. formatter.timeZone = TimeZone(secondsFromGMT: 0)
  9. formatter.timeStyle = .short
  10. return formatter
  11. }
  12. private var rateFormatter: NumberFormatter {
  13. let formatter = NumberFormatter()
  14. formatter.numberStyle = .decimal
  15. formatter.maximumFractionDigits = 2
  16. return formatter
  17. }
  18. var body: some View {
  19. Form {
  20. if let autotune = viewModel.autotune {
  21. Section(header: Text("Autotune")) {
  22. HStack {
  23. Text("Calculated Sensitivity")
  24. Spacer()
  25. if viewModel.units == .mmolL {
  26. Text(rateFormatter.string(from: autotune.sensitivity.asMmolL as NSNumber) ?? "0")
  27. } else {
  28. Text(rateFormatter.string(from: autotune.sensitivity as NSNumber) ?? "0")
  29. }
  30. Text(viewModel.units.rawValue + "/U").foregroundColor(.secondary)
  31. }
  32. }
  33. }
  34. if let newISF = viewModel.autosensISF {
  35. Section(header: Text("Autosens")) {
  36. HStack {
  37. Text("Sensitivity Ratio")
  38. Spacer()
  39. Text(rateFormatter.string(from: viewModel.autosensRatio as NSNumber) ?? "1")
  40. }
  41. HStack {
  42. Text("Calculated Sensitivity")
  43. Spacer()
  44. Text(rateFormatter.string(from: newISF as NSNumber) ?? "0")
  45. Text(viewModel.units.rawValue + "/U").foregroundColor(.secondary)
  46. }
  47. }
  48. }
  49. Section(header: Text("Schedule")) {
  50. list
  51. addButton
  52. }
  53. Section {
  54. Button { viewModel.save() }
  55. label: {
  56. Text("Save")
  57. }
  58. .disabled(viewModel.items.isEmpty)
  59. }
  60. }
  61. .navigationTitle("Insulin Sensitivities")
  62. .navigationBarTitleDisplayMode(.automatic)
  63. .navigationBarItems(
  64. trailing: EditButton()
  65. )
  66. .environment(\.editMode, $editMode)
  67. .onAppear {
  68. viewModel.validate()
  69. }
  70. }
  71. private func pickers(for index: Int) -> some View {
  72. GeometryReader { geometry in
  73. VStack {
  74. HStack {
  75. Text("Rate").frame(width: geometry.size.width / 2)
  76. Text("Time").frame(width: geometry.size.width / 2)
  77. }
  78. HStack(spacing: 0) {
  79. Picker(selection: $viewModel.items[index].rateIndex, label: EmptyView()) {
  80. ForEach(0 ..< viewModel.rateValues.count, id: \.self) { i in
  81. Text(
  82. (
  83. self.rateFormatter
  84. .string(from: viewModel.rateValues[i] as NSNumber) ?? ""
  85. ) + " \(viewModel.units.rawValue)/U"
  86. ).tag(i)
  87. }
  88. }
  89. .frame(maxWidth: geometry.size.width / 2)
  90. .clipped()
  91. Picker(selection: $viewModel.items[index].timeIndex, label: EmptyView()) {
  92. ForEach(0 ..< viewModel.timeValues.count, id: \.self) { i in
  93. Text(
  94. self.dateFormatter
  95. .string(from: Date(
  96. timeIntervalSince1970: viewModel
  97. .timeValues[i]
  98. ))
  99. ).tag(i)
  100. }
  101. }
  102. .frame(maxWidth: geometry.size.width / 2)
  103. .clipped()
  104. }
  105. }
  106. }
  107. }
  108. private var list: some View {
  109. List {
  110. ForEach(viewModel.items.indexed(), id: \.1.id) { index, item in
  111. NavigationLink(destination: pickers(for: index)) {
  112. HStack {
  113. Text("Rate").foregroundColor(.secondary)
  114. Text(
  115. "\(rateFormatter.string(from: viewModel.rateValues[item.rateIndex] as NSNumber) ?? "0") \(viewModel.units.rawValue)/U"
  116. )
  117. Spacer()
  118. Text("starts at").foregroundColor(.secondary)
  119. Text(
  120. "\(dateFormatter.string(from: Date(timeIntervalSince1970: viewModel.timeValues[item.timeIndex])))"
  121. )
  122. }
  123. }
  124. .moveDisabled(true)
  125. }
  126. .onDelete(perform: onDelete)
  127. }
  128. }
  129. private var addButton: some View {
  130. guard viewModel.canAdd else {
  131. return AnyView(EmptyView())
  132. }
  133. switch editMode {
  134. case .inactive:
  135. return AnyView(Button(action: onAdd) { Text("Add") })
  136. default:
  137. return AnyView(EmptyView())
  138. }
  139. }
  140. func onAdd() {
  141. viewModel.add()
  142. }
  143. private func onDelete(offsets: IndexSet) {
  144. viewModel.items.remove(atOffsets: offsets)
  145. viewModel.validate()
  146. }
  147. }
  148. }