ISFEditorRootView.swift 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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 newISF = viewModel.autosensISF {
  21. Section(header: Text("Autosens")) {
  22. HStack {
  23. Text("Sensitivity Ratio").foregroundColor(.secondary)
  24. Spacer()
  25. Text(rateFormatter.string(from: viewModel.autosensRatio as NSNumber) ?? "1")
  26. }
  27. HStack {
  28. Text("Calculated ISF").foregroundColor(.secondary)
  29. Spacer()
  30. Text((rateFormatter.string(from: newISF as NSNumber) ?? "0") + " \(viewModel.units.rawValue)/U")
  31. }
  32. }
  33. }
  34. Section(header: Text("Schedule")) {
  35. list
  36. addButton
  37. }
  38. Section {
  39. Button { viewModel.save() }
  40. label: {
  41. Text("Save")
  42. }
  43. .disabled(viewModel.items.isEmpty)
  44. }
  45. }
  46. .navigationTitle("Insulin Sensitivities")
  47. .navigationBarTitleDisplayMode(.automatic)
  48. .navigationBarItems(
  49. trailing: EditButton()
  50. )
  51. .environment(\.editMode, $editMode)
  52. .onAppear {
  53. viewModel.validate()
  54. }
  55. }
  56. private func pickers(for index: Int) -> some View {
  57. GeometryReader { geometry in
  58. VStack {
  59. HStack {
  60. Text("Rate").frame(width: geometry.size.width / 2)
  61. Text("Time").frame(width: geometry.size.width / 2)
  62. }
  63. HStack(spacing: 0) {
  64. Picker(selection: $viewModel.items[index].rateIndex, label: EmptyView()) {
  65. ForEach(0 ..< viewModel.rateValues.count, id: \.self) { i in
  66. Text(
  67. (
  68. self.rateFormatter
  69. .string(from: viewModel.rateValues[i] as NSNumber) ?? ""
  70. ) + " \(viewModel.units.rawValue)/U"
  71. ).tag(i)
  72. }
  73. }
  74. .frame(maxWidth: geometry.size.width / 2)
  75. .clipped()
  76. Picker(selection: $viewModel.items[index].timeIndex, label: EmptyView()) {
  77. ForEach(0 ..< viewModel.timeValues.count, id: \.self) { i in
  78. Text(
  79. self.dateFormatter
  80. .string(from: Date(
  81. timeIntervalSince1970: viewModel
  82. .timeValues[i]
  83. ))
  84. ).tag(i)
  85. }
  86. }
  87. .frame(maxWidth: geometry.size.width / 2)
  88. .clipped()
  89. }
  90. }
  91. }
  92. }
  93. private var list: some View {
  94. List {
  95. ForEach(viewModel.items.indexed(), id: \.1.id) { index, item in
  96. NavigationLink(destination: pickers(for: index)) {
  97. HStack {
  98. Text("Rate").foregroundColor(.secondary)
  99. Text(
  100. "\(rateFormatter.string(from: viewModel.rateValues[item.rateIndex] as NSNumber) ?? "0") \(viewModel.units.rawValue)/U"
  101. )
  102. Spacer()
  103. Text("starts at").foregroundColor(.secondary)
  104. Text(
  105. "\(dateFormatter.string(from: Date(timeIntervalSince1970: viewModel.timeValues[item.timeIndex])))"
  106. )
  107. }
  108. }
  109. .moveDisabled(true)
  110. }
  111. .onDelete(perform: onDelete)
  112. }
  113. }
  114. private var addButton: some View {
  115. guard viewModel.canAdd else {
  116. return AnyView(EmptyView())
  117. }
  118. switch editMode {
  119. case .inactive:
  120. return AnyView(Button(action: onAdd) { Text("Add") })
  121. default:
  122. return AnyView(EmptyView())
  123. }
  124. }
  125. func onAdd() {
  126. viewModel.add()
  127. }
  128. private func onDelete(offsets: IndexSet) {
  129. viewModel.items.remove(atOffsets: offsets)
  130. viewModel.validate()
  131. }
  132. }
  133. }