TempTargetSetup.swift 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import CoreData
  2. import Foundation
  3. extension Home.StateModel {
  4. func setupTempTargetsStored() {
  5. Task {
  6. let ids = await self.fetchTempTargets()
  7. let tempTargetObjects: [TempTargetStored] = await CoreDataStack.shared
  8. .getNSManagedObject(with: ids, context: viewContext)
  9. await updateTempTargetsArray(with: tempTargetObjects)
  10. }
  11. }
  12. private func fetchTempTargets() async -> [NSManagedObjectID] {
  13. let results = await CoreDataStack.shared.fetchEntitiesAsync(
  14. ofType: TempTargetStored.self,
  15. onContext: tempTargetFetchContext,
  16. predicate: NSPredicate.lastActiveTempTarget,
  17. key: "date",
  18. ascending: false
  19. )
  20. return await tempTargetFetchContext.perform {
  21. guard let fetchedResults = results as? [TempTargetStored] else { return [] }
  22. return fetchedResults.map(\.objectID)
  23. }
  24. }
  25. @MainActor private func updateTempTargetsArray(with objects: [TempTargetStored]) {
  26. tempTargetStored = objects
  27. }
  28. // Setup expired TempTargets
  29. func setupTempTargetsRunStored() {
  30. Task {
  31. let ids = await self.fetchTempTargetRunStored()
  32. let tempTargetRunObjects: [TempTargetRunStored] = await CoreDataStack.shared
  33. .getNSManagedObject(with: ids, context: viewContext)
  34. await updateTempTargetRunStoredArray(with: tempTargetRunObjects)
  35. }
  36. }
  37. private func fetchTempTargetRunStored() async -> [NSManagedObjectID] {
  38. let predicate = NSPredicate(format: "startDate >= %@", Date.oneDayAgo as NSDate)
  39. let results = await CoreDataStack.shared.fetchEntitiesAsync(
  40. ofType: TempTargetRunStored.self,
  41. onContext: tempTargetFetchContext,
  42. predicate: predicate,
  43. key: "startDate",
  44. ascending: false
  45. )
  46. return await tempTargetFetchContext.perform {
  47. guard let fetchedResults = results as? [TempTargetRunStored] else { return [] }
  48. return fetchedResults.map(\.objectID)
  49. }
  50. }
  51. @MainActor private func updateTempTargetRunStoredArray(with objects: [TempTargetRunStored]) {
  52. tempTargetRunStored = objects
  53. }
  54. @MainActor func cancelTempTarget(withID id: NSManagedObjectID) async {
  55. do {
  56. guard let profileToCancel = try viewContext.existingObject(with: id) as? TempTargetStored else { return }
  57. profileToCancel.enabled = false
  58. guard viewContext.hasChanges else { return }
  59. try viewContext.save()
  60. // Do not save Cancel-Temp Targets from Nightscout to RunStoredEntity
  61. if profileToCancel.duration != 0, profileToCancel.target != 0 {
  62. await saveToTempTargetRunStored(object: profileToCancel)
  63. }
  64. // We also need to update the storage for temp targets
  65. tempTargetStorage.saveTempTargetsToStorage([TempTarget.cancel(at: Date())])
  66. Foundation.NotificationCenter.default.post(name: .didUpdateTempTargetConfiguration, object: nil)
  67. } catch let error as NSError {
  68. debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to cancel Temp Target with error: \(error)")
  69. }
  70. }
  71. @MainActor func saveToTempTargetRunStored(object: TempTargetStored) async {
  72. let newTempTargetRunStored = TempTargetRunStored(context: viewContext)
  73. newTempTargetRunStored.id = UUID()
  74. newTempTargetRunStored.name = object.name
  75. newTempTargetRunStored.startDate = object.date ?? .distantPast
  76. newTempTargetRunStored.endDate = Date()
  77. newTempTargetRunStored.target = object.target ?? 0
  78. newTempTargetRunStored.tempTarget = object
  79. newTempTargetRunStored.isUploadedToNS = false
  80. do {
  81. guard viewContext.hasChanges else { return }
  82. try viewContext.save()
  83. } catch let error as NSError {
  84. debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to save Temp Target with error: \(error)")
  85. }
  86. }
  87. func computeAdjustedPercentage(halfBasalTargetValue: Decimal, tempTargetValue: Decimal) -> Int {
  88. let normalTarget: Decimal = 100
  89. let deviationFromNormal = halfBasalTargetValue - normalTarget
  90. let adjustmentFactor = deviationFromNormal + (tempTargetValue - normalTarget)
  91. let adjustmentRatio: Decimal = (deviationFromNormal * adjustmentFactor <= 0) ? maxValue : deviationFromNormal /
  92. adjustmentFactor
  93. return Int(Double(min(adjustmentRatio, maxValue) * 100).rounded())
  94. }
  95. }