DataTableStateModel.swift 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. import CoreData
  2. import SwiftUI
  3. extension DataTable {
  4. final class StateModel: BaseStateModel<Provider> {
  5. @Injected() var broadcaster: Broadcaster!
  6. @Injected() var unlockmanager: UnlockManager!
  7. @Injected() private var storage: FileStorage!
  8. let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
  9. @Published var mode: Mode = .treatments
  10. @Published var treatments: [Treatment] = []
  11. @Published var glucose: [Glucose] = []
  12. @Published var manualGlcuose: Decimal = 0
  13. var units: GlucoseUnits = .mmolL
  14. override func subscribe() {
  15. units = settingsManager.settings.units
  16. setupTreatments()
  17. setupGlucose()
  18. broadcaster.register(SettingsObserver.self, observer: self)
  19. broadcaster.register(PumpHistoryObserver.self, observer: self)
  20. broadcaster.register(TempTargetsObserver.self, observer: self)
  21. broadcaster.register(CarbsObserver.self, observer: self)
  22. broadcaster.register(GlucoseObserver.self, observer: self)
  23. }
  24. private func setupTreatments() {
  25. DispatchQueue.global().async {
  26. let units = self.settingsManager.settings.units
  27. let carbs = self.provider.carbs()
  28. .filter { !($0.isFPU ?? false) }
  29. .map {
  30. if let id = $0.id {
  31. return Treatment(
  32. units: units,
  33. type: .carbs,
  34. date: $0.createdAt,
  35. amount: $0.carbs,
  36. id: id,
  37. note: $0.note
  38. )
  39. } else {
  40. return Treatment(
  41. units: units,
  42. type: .carbs,
  43. date: $0.createdAt,
  44. amount: $0.carbs,
  45. note: $0.note
  46. )
  47. }
  48. }
  49. let fpus = self.provider.fpus()
  50. .filter { $0.isFPU ?? false }
  51. .map {
  52. Treatment(
  53. units: units,
  54. type: .fpus,
  55. date: $0.createdAt,
  56. amount: $0.carbs,
  57. id: $0.id,
  58. isFPU: $0.isFPU,
  59. fpuID: $0.fpuID,
  60. note: $0.note
  61. )
  62. }
  63. let boluses = self.provider.pumpHistory()
  64. .filter { $0.type == .bolus }
  65. .map {
  66. Treatment(units: units, type: .bolus, date: $0.timestamp, amount: $0.amount, idPumpEvent: $0.id)
  67. }
  68. let tempBasals = self.provider.pumpHistory()
  69. .filter { $0.type == .tempBasal || $0.type == .tempBasalDuration }
  70. .chunks(ofCount: 2)
  71. .compactMap { chunk -> Treatment? in
  72. let chunk = Array(chunk)
  73. guard chunk.count == 2, chunk[0].type == .tempBasal,
  74. chunk[1].type == .tempBasalDuration else { return nil }
  75. return Treatment(
  76. units: units,
  77. type: .tempBasal,
  78. date: chunk[0].timestamp,
  79. amount: chunk[0].rate ?? 0,
  80. secondAmount: nil,
  81. duration: Decimal(chunk[1].durationMin ?? 0)
  82. )
  83. }
  84. let tempTargets = self.provider.tempTargets()
  85. .map {
  86. Treatment(
  87. units: units,
  88. type: .tempTarget,
  89. date: $0.createdAt,
  90. amount: $0.targetBottom ?? 0,
  91. secondAmount: $0.targetTop,
  92. duration: $0.duration
  93. )
  94. }
  95. let suspend = self.provider.pumpHistory()
  96. .filter { $0.type == .pumpSuspend }
  97. .map {
  98. Treatment(units: units, type: .suspend, date: $0.timestamp)
  99. }
  100. let resume = self.provider.pumpHistory()
  101. .filter { $0.type == .pumpResume }
  102. .map {
  103. Treatment(units: units, type: .resume, date: $0.timestamp)
  104. }
  105. DispatchQueue.main.async {
  106. self.treatments = [carbs, boluses, tempBasals, tempTargets, suspend, resume, fpus]
  107. .flatMap { $0 }
  108. .sorted { $0.date > $1.date }
  109. }
  110. }
  111. }
  112. func setupGlucose() {
  113. DispatchQueue.main.async {
  114. self.glucose = self.provider.glucose().map(Glucose.init)
  115. }
  116. }
  117. func deleteCarbs(_ treatment: Treatment) {
  118. provider.deleteCarbs(treatment)
  119. }
  120. func deleteInsulin(_ treatment: Treatment) {
  121. unlockmanager.unlock()
  122. .sink { _ in } receiveValue: { [weak self] _ in
  123. guard let self = self else { return }
  124. self.provider.deleteInsulin(treatment)
  125. }
  126. .store(in: &lifetime)
  127. }
  128. func deleteGlucose(at index: Int) {
  129. let id = glucose[index].id
  130. provider.deleteGlucose(id: id)
  131. let fetchRequest: NSFetchRequest<NSFetchRequestResult>
  132. fetchRequest = NSFetchRequest(entityName: "Readings")
  133. fetchRequest.predicate = NSPredicate(format: "id == %@", id)
  134. let deleteRequest = NSBatchDeleteRequest(
  135. fetchRequest: fetchRequest
  136. )
  137. deleteRequest.resultType = .resultTypeObjectIDs
  138. do {
  139. let deleteResult = try coredataContext.execute(deleteRequest) as? NSBatchDeleteResult
  140. if let objectIDs = deleteResult?.result as? [NSManagedObjectID] {
  141. NSManagedObjectContext.mergeChanges(
  142. fromRemoteContextSave: [NSDeletedObjectsKey: objectIDs],
  143. into: [coredataContext]
  144. )
  145. }
  146. } catch {
  147. // To do: handle any thrown errors.
  148. }
  149. // try? coredataContext.save()
  150. }
  151. func addManualGlucose() {
  152. let glucose = units == .mmolL ? manualGlcuose.asMgdL : manualGlcuose
  153. let now = Date()
  154. let id = UUID().uuidString
  155. let saveToJSON = BloodGlucose(
  156. _id: id,
  157. direction: nil,
  158. date: Decimal(now.timeIntervalSince1970) * 1000,
  159. dateString: now,
  160. unfiltered: nil,
  161. filtered: nil,
  162. noise: nil,
  163. glucose: Int(glucose),
  164. type: "Manual"
  165. )
  166. provider.glucoseStorage.storeGlucose([saveToJSON])
  167. debug(.default, "Manual Glucose saved to glucose.json")
  168. }
  169. }
  170. }
  171. extension DataTable.StateModel:
  172. SettingsObserver,
  173. PumpHistoryObserver,
  174. TempTargetsObserver,
  175. CarbsObserver,
  176. GlucoseObserver
  177. {
  178. func settingsDidChange(_: FreeAPSSettings) {
  179. setupTreatments()
  180. }
  181. func pumpHistoryDidUpdate(_: [PumpHistoryEvent]) {
  182. setupTreatments()
  183. }
  184. func tempTargetsDidUpdate(_: [TempTarget]) {
  185. setupTreatments()
  186. }
  187. func carbsDidUpdate(_: [CarbsEntry]) {
  188. setupTreatments()
  189. }
  190. func glucoseDidUpdate(_: [BloodGlucose]) {
  191. setupGlucose()
  192. }
  193. }