NightscoutConfigRootView.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import CoreData
  2. import SwiftUI
  3. import Swinject
  4. extension NightscoutConfig {
  5. struct RootView: BaseView {
  6. let resolver: Resolver
  7. let displayClose: Bool
  8. @StateObject var state = StateModel()
  9. <<<<<<< HEAD
  10. @State var importAlert: Alert?
  11. @State var isImportAlertPresented = false
  12. @State var importedHasRun = false
  13. @Environment(\.colorScheme) var colorScheme
  14. var color: LinearGradient {
  15. colorScheme == .dark ? LinearGradient(
  16. gradient: Gradient(colors: [
  17. Color.bgDarkBlue,
  18. Color.bgDarkerDarkBlue
  19. ]),
  20. startPoint: .top,
  21. endPoint: .bottom
  22. )
  23. :
  24. LinearGradient(
  25. gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
  26. startPoint: .top,
  27. endPoint: .bottom
  28. )
  29. }
  30. @FetchRequest(
  31. entity: ImportError.entity(),
  32. sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)], predicate: NSPredicate(
  33. format: "date > %@", Date().addingTimeInterval(-1.minutes.timeInterval) as NSDate
  34. )
  35. ) var fetchedErrors: FetchedResults<ImportError>
  36. private var portFormater: NumberFormatter {
  37. let formatter = NumberFormatter()
  38. formatter.allowsFloats = false
  39. formatter.usesGroupingSeparator = false
  40. return formatter
  41. }
  42. =======
  43. @State private var importAlert: Alert?
  44. @State private var isImportAlertPresented = false
  45. @State private var importedHasRun = false
  46. @FetchRequest(
  47. entity: ImportError.entity(),
  48. sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)],
  49. predicate: NSPredicate(format: "date > %@", Date().addingTimeInterval(-1.minutes.timeInterval) as NSDate)
  50. ) var fetchedErrors: FetchedResults<ImportError>
  51. >>>>>>> 9672da256c317a314acc76d6e4f6e82cc174d133
  52. var body: some View {
  53. Form {
  54. NavigationLink("Connect", destination: NightscoutConnectView(state: state))
  55. NavigationLink("Upload", destination: NightscoutUploadView(state: state))
  56. NavigationLink("Fetch and Remote Control", destination: NightscoutFetchView(state: state))
  57. Section(
  58. header: Text("Import Settings from Nightscout"),
  59. footer: VStack(alignment: .leading, spacing: 2) {
  60. Text(
  61. "Importing settings from Nightscout will overwrite these settings in Trio Settings -> Configuration:"
  62. )
  63. Text(" • ") + Text("DIA (Pump settings)")
  64. Text(" • ") + Text("Basal Profile")
  65. Text(" • ") + Text("Insulin Sensitivities")
  66. Text(" • ") + Text("Carb Ratios")
  67. Text(" • ") + Text("Target Glucose")
  68. }
  69. ) {
  70. Button("Import settings") {
  71. importAlert = Alert(
  72. title: Text("Import settings?"),
  73. message: Text(
  74. "\n" +
  75. NSLocalizedString(
  76. "This will replace some or all of your current pump settings. Are you sure you want to import profile settings from Nightscout?",
  77. comment: "Profile Import Alert"
  78. ) +
  79. "\n"
  80. ),
  81. primaryButton: .destructive(
  82. Text("Yes, Import"),
  83. action: {
  84. state.importSettings()
  85. importedHasRun = true
  86. }
  87. ),
  88. secondaryButton: .cancel()
  89. )
  90. isImportAlertPresented.toggle()
  91. }.disabled(state.url.isEmpty || state.connecting)
  92. .alert(isPresented: $importedHasRun) {
  93. Alert(
  94. title: Text((fetchedErrors.first?.error ?? "").count < 4 ? "Settings imported" : "Import Error"),
  95. message: Text(
  96. (fetchedErrors.first?.error ?? "").count < 4 ?
  97. NSLocalizedString(
  98. "\nNow please verify all of your new settings thoroughly: \n\n • DIA (Pump settings)\n • Basal Profile\n • Insulin Sensitivities\n • Carb Ratios\n • Target Glucose\n\n in Trio Settings -> Configuration.\n\nBad or invalid profile settings could have disastrous effects.",
  99. comment: "Imported Profiles Alert"
  100. ) :
  101. NSLocalizedString(fetchedErrors.first?.error ?? "", comment: "Import Error")
  102. ),
  103. primaryButton: .destructive(
  104. Text("OK")
  105. ),
  106. secondaryButton: .cancel()
  107. )
  108. }
  109. }
  110. <<<<<<< HEAD
  111. Section {
  112. Button("Connect") { state.connect() }
  113. .disabled(state.url.isEmpty || state.connecting)
  114. Button("Delete") { state.delete() }.foregroundColor(.red).disabled(state.connecting)
  115. }
  116. Section {
  117. Toggle("Upload", isOn: $state.isUploadEnabled)
  118. if state.isUploadEnabled {
  119. Toggle("Statistics", isOn: $state.uploadStats)
  120. HStack(alignment: .top) {
  121. Image(systemName: "pencil.circle.fill")
  122. VStack {
  123. Text(
  124. "This enables uploading of statistics.json to Nightscout, which can be used by the Community Statistics and Demographics Project.\n\nParticipation in Community Statistics is opt-in, and requires separate registration at:\n"
  125. )
  126. .font(.caption)
  127. Text(
  128. "https://iaps-stats.hub.org"
  129. )
  130. .font(.caption)
  131. .multilineTextAlignment(.center)
  132. }
  133. }
  134. .foregroundColor(Color.secondary)
  135. Toggle("Glucose", isOn: $state.uploadGlucose)
  136. }
  137. } header: {
  138. Text("Allow Uploads")
  139. }
  140. Section {
  141. Button("Import settings from Nightscout") {
  142. importAlert = Alert(
  143. title: Text("Import settings?"),
  144. message: Text(
  145. "\n" +
  146. NSLocalizedString(
  147. "This will replace some or all of your current pump settings. Are you sure you want to import profile settings from Nightscout?",
  148. comment: "Profile Import Alert"
  149. ) +
  150. "\n"
  151. ),
  152. primaryButton: .destructive(
  153. Text("Yes, Import"),
  154. action: {
  155. state.importSettings()
  156. importedHasRun = true
  157. }
  158. ),
  159. secondaryButton: .cancel()
  160. )
  161. isImportAlertPresented.toggle()
  162. }.disabled(state.url.isEmpty || state.connecting)
  163. } header: { Text("Import from Nightscout") }
  164. .alert(isPresented: $importedHasRun) {
  165. Alert(
  166. title: Text((fetchedErrors.first?.error ?? "").count < 4 ? "Settings imported" : "Import Error"),
  167. message: Text(
  168. (fetchedErrors.first?.error ?? "").count < 4 ?
  169. NSLocalizedString(
  170. "\nNow please verify all of your new settings thoroughly:\n\n* Basal Settings\n * Carb Ratios\n * Glucose Targets\n * Insulin Sensitivities\n * DIA\n\n in iAPS Settings > Configuration.\n\nBad or invalid profile settings could have disatrous effects.",
  171. comment: "Imported Profiles Alert"
  172. ) :
  173. NSLocalizedString(fetchedErrors.first?.error ?? "", comment: "Import Error")
  174. ),
  175. primaryButton: .destructive(
  176. Text("OK")
  177. ),
  178. secondaryButton: .cancel()
  179. )
  180. }
  181. Section {
  182. Toggle("Use local glucose server", isOn: $state.useLocalSource)
  183. HStack {
  184. Text("Port")
  185. TextFieldWithToolBar(
  186. text: $state.localPort,
  187. placeholder: "",
  188. keyboardType: .numberPad,
  189. numberFormatter: portFormater,
  190. allowDecimalSeparator: false
  191. )
  192. }
  193. } header: { Text("Local glucose source") }
  194. Section {
  195. Button("Backfill glucose") {
  196. Task {
  197. await state.backfillGlucose()
  198. }
  199. }
  200. .disabled(state.url.isEmpty || state.connecting || state.backfilling)
  201. }
  202. Section {
  203. Toggle("Remote control", isOn: $state.allowAnnouncements)
  204. } header: { Text("Allow Remote control of iAPS") }
  205. }
  206. .scrollContentBackground(.hidden).background(color)
  207. .onAppear(perform: configureView)
  208. .navigationBarTitle("Nightscout Config")
  209. .navigationBarTitleDisplayMode(.automatic)
  210. .alert(isPresented: $isImportAlertPresented) {
  211. importAlert!
  212. }
  213. =======
  214. Section {
  215. Button("Backfill glucose") { state.backfillGlucose() }
  216. .disabled(state.url.isEmpty || state.connecting || state.backfilling)
  217. } header: { Text("Backfill glucose from Nightscout")
  218. }
  219. }
  220. .navigationBarTitle("Nightscout Config")
  221. .navigationBarTitleDisplayMode(.automatic)
  222. .navigationBarItems(leading: displayClose ? Button("Close", action: state.hideModal) : nil)
  223. .alert(isPresented: $isImportAlertPresented) {
  224. importAlert!
  225. }
  226. .onAppear(perform: configureView)
  227. >>>>>>> 9672da256c317a314acc76d6e4f6e82cc174d133
  228. }
  229. }
  230. }