CalibrationsStateModel.swift 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import CoreData
  2. import Observation
  3. import SwiftDate
  4. import SwiftUI
  5. extension Calibrations {
  6. @Observable final class StateModel: BaseStateModel<Provider> {
  7. @ObservationIgnored @Injected() var glucoseStorage: GlucoseStorage!
  8. @ObservationIgnored @Injected() var calibrationService: CalibrationService!
  9. var slope: Double = 1
  10. var intercept: Double = 1
  11. var newCalibration: Decimal = 0
  12. var calibrations: [Calibration] = []
  13. var calibrate: (Int) -> Double = { Double($0) }
  14. var items: [Item] = []
  15. var units: GlucoseUnits = .mgdL
  16. let backgroundContext = CoreDataStack.shared.newTaskContext()
  17. private let viewContext = CoreDataStack.shared.persistentContainer.viewContext
  18. override func subscribe() {
  19. units = settingsManager.settings.units
  20. calibrate = calibrationService.calibrate
  21. setupCalibrations()
  22. }
  23. private func setupCalibrations() {
  24. slope = calibrationService.slope
  25. intercept = calibrationService.intercept
  26. calibrations = calibrationService.calibrations
  27. items = calibrations.map {
  28. Item(calibration: $0)
  29. }
  30. }
  31. /// - Returns: An array of NSManagedObjectIDs for glucose readings.
  32. private func fetchGlucose() async throws -> [NSManagedObjectID] {
  33. let results = try await CoreDataStack.shared.fetchEntitiesAsync(
  34. ofType: GlucoseStored.self,
  35. onContext: backgroundContext,
  36. predicate: NSPredicate.predicateFor20MinAgo,
  37. key: "date",
  38. ascending: false,
  39. fetchLimit: 1 /// We only need the last value
  40. )
  41. return try await backgroundContext.perform {
  42. guard let glucoseResults = results as? [GlucoseStored] else {
  43. throw CoreDataError.fetchError(function: #function, file: #file)
  44. }
  45. return glucoseResults.map(\.objectID)
  46. }
  47. }
  48. @MainActor func addCalibration() async {
  49. do {
  50. defer {
  51. UIApplication.shared.endEditing()
  52. setupCalibrations()
  53. }
  54. var glucose = newCalibration
  55. if units == .mmolL {
  56. glucose = newCalibration.asMgdL
  57. }
  58. let glucoseValuesIds = try await fetchGlucose()
  59. let glucoseObjects: [GlucoseStored] = try await CoreDataStack.shared
  60. .getNSManagedObject(with: glucoseValuesIds, context: viewContext)
  61. if let lastGlucose = glucoseObjects.first {
  62. let unfiltered = lastGlucose.glucose
  63. let calibration = Calibration(x: Double(unfiltered), y: Double(glucose))
  64. calibrationService.addCalibration(calibration)
  65. } else {
  66. info(.service, "Glucose is stale for calibration")
  67. return
  68. }
  69. } catch {
  70. debug(.default, "\(DebuggingIdentifiers.failed) Failed to add calibration: \(error.localizedDescription)")
  71. }
  72. }
  73. func removeLast() {
  74. calibrationService.removeLast()
  75. setupCalibrations()
  76. }
  77. func removeAll() {
  78. calibrationService.removeAllCalibrations()
  79. setupCalibrations()
  80. }
  81. func removeAtIndex(_ index: Int) {
  82. let calibration = calibrations[index]
  83. calibrationService.removeCalibration(calibration)
  84. setupCalibrations()
  85. }
  86. }
  87. }