ISFEditorStateModel.swift 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import CoreData
  2. import Observation
  3. import SwiftUI
  4. extension ISFEditor {
  5. @Observable final class StateModel: BaseStateModel<Provider> {
  6. @ObservationIgnored @Injected() var determinationStorage: DeterminationStorage!
  7. @ObservationIgnored @Injected() private var nightscout: NightscoutManager!
  8. var items: [Item] = []
  9. var initialItems: [Item] = []
  10. var shouldDisplaySaving: Bool = false
  11. let context = CoreDataStack.shared.newTaskContext()
  12. let timeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
  13. var rateValues: [Decimal] {
  14. var values = stride(from: 9, to: 540.01, by: 1.0).map { Decimal($0) }
  15. if units == .mmolL {
  16. values = values.filter { Int(truncating: $0 as NSNumber) % 2 == 0 }
  17. }
  18. return values
  19. }
  20. var canAdd: Bool {
  21. guard let lastItem = items.last else { return true }
  22. return lastItem.timeIndex < timeValues.count - 1
  23. }
  24. var hasChanges: Bool {
  25. initialItems != items
  26. }
  27. private(set) var units: GlucoseUnits = .mgdL
  28. override func subscribe() {
  29. units = settingsManager.settings.units
  30. let profile = provider.profile
  31. items = profile.sensitivities.map { value in
  32. let timeIndex = timeValues.firstIndex(of: Double(value.offset * 60)) ?? 0
  33. let rateIndex = rateValues.firstIndex(of: value.sensitivity) ?? 0
  34. return Item(rateIndex: rateIndex, timeIndex: timeIndex)
  35. }
  36. initialItems = items.map { Item(rateIndex: $0.rateIndex, timeIndex: $0.timeIndex) }
  37. }
  38. func add() {
  39. var time = 0
  40. var rate = 0
  41. if let last = items.last {
  42. time = last.timeIndex + 1
  43. rate = last.rateIndex
  44. }
  45. let newItem = Item(rateIndex: rate, timeIndex: time)
  46. items.append(newItem)
  47. }
  48. func save() {
  49. guard hasChanges else { return }
  50. shouldDisplaySaving.toggle()
  51. let sensitivities = items.map { item -> InsulinSensitivityEntry in
  52. let fotmatter = DateFormatter()
  53. fotmatter.timeZone = TimeZone(secondsFromGMT: 0)
  54. fotmatter.dateFormat = "HH:mm:ss"
  55. let date = Date(timeIntervalSince1970: self.timeValues[item.timeIndex])
  56. let minutes = Int(date.timeIntervalSince1970 / 60)
  57. let rate = self.rateValues[item.rateIndex]
  58. return InsulinSensitivityEntry(sensitivity: rate, offset: minutes, start: fotmatter.string(from: date))
  59. }
  60. let profile = InsulinSensitivities(
  61. units: .mgdL,
  62. userPreferredUnits: .mgdL,
  63. sensitivities: sensitivities
  64. )
  65. provider.saveProfile(profile)
  66. initialItems = items.map { Item(rateIndex: $0.rateIndex, timeIndex: $0.timeIndex) }
  67. Task.detached(priority: .low) {
  68. debug(.nightscout, "Attempting to upload ISF to Nightscout")
  69. await self.nightscout.uploadProfiles()
  70. }
  71. }
  72. func validate() {
  73. DispatchQueue.main.async {
  74. DispatchQueue.main.async {
  75. let uniq = Array(Set(self.items))
  76. let sorted = uniq.sorted { $0.timeIndex < $1.timeIndex }
  77. sorted.first?.timeIndex = 0
  78. if self.items != sorted {
  79. self.items = sorted
  80. }
  81. if self.items.isEmpty {
  82. self.units = self.settingsManager.settings.units
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. extension ISFEditor.StateModel: SettingsObserver {
  90. func settingsDidChange(_: FreeAPSSettings) {
  91. units = settingsManager.settings.units
  92. }
  93. }