OverrideProfilesStateModel.swift 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. import CoreData
  2. import SwiftUI
  3. extension OverrideProfilesConfig {
  4. final class StateModel: BaseStateModel<Provider> {
  5. @Injected() var storage: TempTargetsStorage!
  6. @Injected() var apsManager: APSManager!
  7. @Published var percentageProfiles: Double = 100
  8. @Published var isEnabled = false
  9. @Published var _indefinite = true
  10. @Published var durationProfile: Decimal = 0
  11. @Published var target: Decimal = 0
  12. @Published var override_target: Bool = false
  13. @Published var smbIsOff: Bool = false
  14. @Published var id: String = ""
  15. @Published var profileName: String = ""
  16. @Published var isPreset: Bool = false
  17. @Published var presetsProfiles: [OverridePresets] = []
  18. @Published var selection: OverridePresets?
  19. @Published var advancedSettings: Bool = false
  20. @Published var isfAndCr: Bool = true
  21. @Published var isf: Bool = true
  22. @Published var cr: Bool = true
  23. @Published var smbIsAlwaysOff: Bool = false
  24. @Published var start: Decimal = 0
  25. @Published var end: Decimal = 23
  26. @Published var smbMinutes: Decimal = 0
  27. @Published var uamMinutes: Decimal = 0
  28. @Published var defaultSmbMinutes: Decimal = 0
  29. @Published var defaultUamMinutes: Decimal = 0
  30. @Published var selectedTab: Tab = .profiles
  31. var units: GlucoseUnits = .mmolL
  32. // temp target stuff
  33. @Published var low: Decimal = 0
  34. // @Published var target: Decimal = 0
  35. @Published var high: Decimal = 0
  36. @Published var durationTT: Decimal = 0
  37. @Published var date = Date()
  38. @Published var newPresetName = ""
  39. @Published var presetsTT: [TempTarget] = []
  40. @Published var percentageTT = 100.0
  41. @Published var maxValue: Decimal = 1.2
  42. @Published var viewPercantage = false
  43. @Published var hbt: Double = 160
  44. @Published var didSaveSettings: Bool = false
  45. override func subscribe() {
  46. units = settingsManager.settings.units
  47. defaultSmbMinutes = settingsManager.preferences.maxSMBBasalMinutes
  48. defaultUamMinutes = settingsManager.preferences.maxUAMSMBBasalMinutes
  49. presetsProfiles = [OverridePresets(context: coredataContext)]
  50. presetsTT = storage.presets()
  51. maxValue = settingsManager.preferences.autosensMax
  52. }
  53. let coredataContext = CoreDataStack.shared.persistentContainer.newBackgroundContext()
  54. func saveSettings() {
  55. coredataContext.perform { [self] in
  56. let saveOverride = Override(context: self.coredataContext)
  57. saveOverride.duration = self.durationProfile as NSDecimalNumber
  58. saveOverride.indefinite = self._indefinite
  59. saveOverride.percentage = self.percentageProfiles
  60. saveOverride.enabled = true
  61. saveOverride.smbIsOff = self.smbIsOff
  62. if self.isPreset {
  63. saveOverride.isPreset = true
  64. saveOverride.id = id
  65. } else { saveOverride.isPreset = false }
  66. saveOverride.date = Date()
  67. if override_target {
  68. if units == .mmolL {
  69. target = target.asMgdL
  70. }
  71. saveOverride.target = target as NSDecimalNumber
  72. } else { saveOverride.target = 0 }
  73. if advancedSettings {
  74. saveOverride.advancedSettings = true
  75. if !isfAndCr {
  76. saveOverride.isfAndCr = false
  77. saveOverride.isf = isf
  78. saveOverride.cr = cr
  79. } else { saveOverride.isfAndCr = true }
  80. if smbIsAlwaysOff {
  81. saveOverride.smbIsAlwaysOff = true
  82. saveOverride.start = start as NSDecimalNumber
  83. saveOverride.end = end as NSDecimalNumber
  84. } else { saveOverride.smbIsAlwaysOff = false }
  85. saveOverride.smbMinutes = smbMinutes as NSDecimalNumber
  86. saveOverride.uamMinutes = uamMinutes as NSDecimalNumber
  87. }
  88. do {
  89. guard self.coredataContext.hasChanges else { return }
  90. try self.coredataContext.save()
  91. } catch {
  92. print(error.localizedDescription)
  93. }
  94. }
  95. }
  96. func savePreset() {
  97. coredataContext.perform { [self] in
  98. let saveOverride = OverridePresets(context: self.coredataContext)
  99. saveOverride.duration = self.durationProfile as NSDecimalNumber
  100. saveOverride.indefinite = self._indefinite
  101. saveOverride.percentage = self.percentageProfiles
  102. saveOverride.smbIsOff = self.smbIsOff
  103. saveOverride.name = self.profileName
  104. id = UUID().uuidString
  105. self.isPreset.toggle()
  106. saveOverride.id = id
  107. saveOverride.date = Date()
  108. if override_target {
  109. saveOverride.target = (
  110. units == .mmolL
  111. ? target.asMgdL
  112. : target
  113. ) as NSDecimalNumber
  114. } else { saveOverride.target = 0 }
  115. if advancedSettings {
  116. saveOverride.advancedSettings = true
  117. if !isfAndCr {
  118. saveOverride.isfAndCr = false
  119. saveOverride.isf = isf
  120. saveOverride.cr = cr
  121. } else { saveOverride.isfAndCr = true }
  122. if smbIsAlwaysOff {
  123. saveOverride.smbIsAlwaysOff = true
  124. saveOverride.start = start as NSDecimalNumber
  125. saveOverride.end = end as NSDecimalNumber
  126. } else { smbIsAlwaysOff = false }
  127. saveOverride.smbMinutes = smbMinutes as NSDecimalNumber
  128. saveOverride.uamMinutes = uamMinutes as NSDecimalNumber
  129. }
  130. do {
  131. guard self.coredataContext.hasChanges else { return }
  132. try self.coredataContext.save()
  133. } catch {
  134. print(error.localizedDescription)
  135. }
  136. }
  137. }
  138. func selectProfile(id_: String) {
  139. guard id_ != "" else { return }
  140. coredataContext.performAndWait {
  141. var profileArray = [OverridePresets]()
  142. let requestProfiles = OverridePresets.fetchRequest() as NSFetchRequest<OverridePresets>
  143. try? profileArray = coredataContext.fetch(requestProfiles)
  144. guard let profile = profileArray.filter({ $0.id == id_ }).first else { return }
  145. let saveOverride = Override(context: self.coredataContext)
  146. saveOverride.duration = (profile.duration ?? 0) as NSDecimalNumber
  147. saveOverride.indefinite = profile.indefinite
  148. saveOverride.percentage = profile.percentage
  149. saveOverride.enabled = true
  150. saveOverride.smbIsOff = profile.smbIsOff
  151. saveOverride.isPreset = true
  152. saveOverride.date = Date()
  153. saveOverride.target = profile.target
  154. saveOverride.id = id_
  155. if profile.advancedSettings {
  156. saveOverride.advancedSettings = true
  157. if !isfAndCr {
  158. saveOverride.isfAndCr = false
  159. saveOverride.isf = profile.isf
  160. saveOverride.cr = profile.cr
  161. } else { saveOverride.isfAndCr = true }
  162. if profile.smbIsAlwaysOff {
  163. saveOverride.smbIsAlwaysOff = true
  164. saveOverride.start = profile.start
  165. saveOverride.end = profile.end
  166. } else { saveOverride.smbIsAlwaysOff = false }
  167. saveOverride.smbMinutes = (profile.smbMinutes ?? 0) as NSDecimalNumber
  168. saveOverride.uamMinutes = (profile.uamMinutes ?? 0) as NSDecimalNumber
  169. }
  170. do {
  171. guard self.coredataContext.hasChanges else { return }
  172. try self.coredataContext.save()
  173. } catch {
  174. print(error.localizedDescription)
  175. }
  176. }
  177. }
  178. func savedSettings() {
  179. coredataContext.performAndWait {
  180. var overrideArray = [Override]()
  181. let requestEnabled = Override.fetchRequest() as NSFetchRequest<Override>
  182. let sortIsEnabled = NSSortDescriptor(key: "date", ascending: false)
  183. requestEnabled.sortDescriptors = [sortIsEnabled]
  184. // requestEnabled.fetchLimit = 1
  185. try? overrideArray = coredataContext.fetch(requestEnabled)
  186. isEnabled = overrideArray.first?.enabled ?? false
  187. percentageProfiles = overrideArray.first?.percentage ?? 100
  188. _indefinite = overrideArray.first?.indefinite ?? true
  189. durationProfile = (overrideArray.first?.duration ?? 0) as Decimal
  190. smbIsOff = overrideArray.first?.smbIsOff ?? false
  191. advancedSettings = overrideArray.first?.advancedSettings ?? false
  192. isfAndCr = overrideArray.first?.isfAndCr ?? true
  193. smbIsAlwaysOff = overrideArray.first?.smbIsAlwaysOff ?? false
  194. if advancedSettings {
  195. if !isfAndCr {
  196. isf = overrideArray.first?.isf ?? false
  197. cr = overrideArray.first?.cr ?? false
  198. }
  199. if smbIsAlwaysOff {
  200. start = (overrideArray.first?.start ?? 0) as Decimal
  201. end = (overrideArray.first?.end ?? 0) as Decimal
  202. }
  203. if (overrideArray[0].smbMinutes as Decimal?) != nil {
  204. smbMinutes = (overrideArray.first?.smbMinutes ?? 30) as Decimal
  205. }
  206. if (overrideArray[0].uamMinutes as Decimal?) != nil {
  207. uamMinutes = (overrideArray.first?.uamMinutes ?? 30) as Decimal
  208. }
  209. }
  210. let overrideTarget = (overrideArray.first?.target ?? 0) as Decimal
  211. var newDuration = Double(durationProfile)
  212. if isEnabled {
  213. let duration = overrideArray.first?.duration ?? 0
  214. let addedMinutes = Int(duration as Decimal)
  215. let date = overrideArray.first?.date ?? Date()
  216. if date.addingTimeInterval(addedMinutes.minutes.timeInterval) < Date(), !_indefinite {
  217. isEnabled = false
  218. }
  219. newDuration = Date().distance(to: date.addingTimeInterval(addedMinutes.minutes.timeInterval)).minutes
  220. if overrideTarget != 0 {
  221. override_target = true
  222. target = units == .mmolL ? overrideTarget.asMmolL : overrideTarget
  223. }
  224. }
  225. if newDuration < 0 { newDuration = 0 } else { durationProfile = Decimal(newDuration) }
  226. if !isEnabled {
  227. _indefinite = true
  228. percentageProfiles = 100
  229. durationProfile = 0
  230. target = 0
  231. override_target = false
  232. smbIsOff = false
  233. advancedSettings = false
  234. smbMinutes = defaultSmbMinutes
  235. uamMinutes = defaultUamMinutes
  236. }
  237. }
  238. }
  239. func cancelProfile() {
  240. _indefinite = true
  241. isEnabled = false
  242. percentageProfiles = 100
  243. durationProfile = 0
  244. target = 0
  245. override_target = false
  246. smbIsOff = false
  247. advancedSettings = false
  248. coredataContext.perform { [self] in
  249. let profiles = Override(context: self.coredataContext)
  250. profiles.enabled = false
  251. profiles.date = Date()
  252. do {
  253. guard self.coredataContext.hasChanges else { return }
  254. try self.coredataContext.save()
  255. } catch {
  256. print(error.localizedDescription)
  257. }
  258. }
  259. smbMinutes = defaultSmbMinutes
  260. uamMinutes = defaultUamMinutes
  261. }
  262. // MARK: TEMP TARGET
  263. func enact() {
  264. guard durationTT > 0 else {
  265. return
  266. }
  267. var lowTarget = low
  268. if viewPercantage {
  269. lowTarget = Decimal(round(Double(computeTarget())))
  270. coredataContext.performAndWait {
  271. let saveToCoreData = TempTargets(context: self.coredataContext)
  272. saveToCoreData.id = UUID().uuidString
  273. saveToCoreData.active = true
  274. saveToCoreData.hbt = hbt
  275. saveToCoreData.date = Date()
  276. saveToCoreData.duration = durationTT as NSDecimalNumber
  277. saveToCoreData.startDate = Date()
  278. try? self.coredataContext.save()
  279. }
  280. didSaveSettings = true
  281. } else {
  282. coredataContext.performAndWait {
  283. let saveToCoreData = TempTargets(context: coredataContext)
  284. saveToCoreData.active = false
  285. saveToCoreData.date = Date()
  286. do {
  287. guard self.coredataContext.hasChanges else { return }
  288. try self.coredataContext.save()
  289. } catch {
  290. print(error.localizedDescription)
  291. }
  292. }
  293. }
  294. var highTarget = lowTarget
  295. if units == .mmolL, !viewPercantage {
  296. lowTarget = Decimal(round(Double(lowTarget.asMgdL)))
  297. highTarget = lowTarget
  298. }
  299. let entry = TempTarget(
  300. name: TempTarget.custom,
  301. createdAt: date,
  302. targetTop: highTarget,
  303. targetBottom: lowTarget,
  304. duration: durationTT,
  305. enteredBy: TempTarget.manual,
  306. reason: TempTarget.custom
  307. )
  308. storage.storeTempTargets([entry])
  309. showModal(for: nil)
  310. }
  311. func cancel() {
  312. storage.storeTempTargets([TempTarget.cancel(at: Date())])
  313. showModal(for: nil)
  314. coredataContext.performAndWait {
  315. let saveToCoreData = TempTargets(context: self.coredataContext)
  316. saveToCoreData.active = false
  317. saveToCoreData.date = Date()
  318. do {
  319. guard self.coredataContext.hasChanges else { return }
  320. try self.coredataContext.save()
  321. } catch {
  322. print(error.localizedDescription)
  323. }
  324. let setHBT = TempTargetsSlider(context: self.coredataContext)
  325. setHBT.enabled = false
  326. setHBT.date = Date()
  327. do {
  328. guard self.coredataContext.hasChanges else { return }
  329. try self.coredataContext.save()
  330. } catch {
  331. print(error.localizedDescription)
  332. }
  333. }
  334. }
  335. func save() {
  336. guard durationTT > 0 else {
  337. return
  338. }
  339. var lowTarget = low
  340. if viewPercantage {
  341. lowTarget = Decimal(round(Double(computeTarget())))
  342. didSaveSettings = true
  343. }
  344. var highTarget = lowTarget
  345. if units == .mmolL, !viewPercantage {
  346. lowTarget = Decimal(round(Double(lowTarget.asMgdL)))
  347. highTarget = lowTarget
  348. }
  349. let entry = TempTarget(
  350. name: newPresetName.isEmpty ? TempTarget.custom : newPresetName,
  351. createdAt: Date(),
  352. targetTop: highTarget,
  353. targetBottom: lowTarget,
  354. duration: durationTT,
  355. enteredBy: TempTarget.manual,
  356. reason: newPresetName.isEmpty ? TempTarget.custom : newPresetName
  357. )
  358. presetsTT.append(entry)
  359. storage.storePresets(presetsTT)
  360. if viewPercantage {
  361. let id = entry.id
  362. coredataContext.performAndWait {
  363. let saveToCoreData = TempTargetsSlider(context: self.coredataContext)
  364. saveToCoreData.id = id
  365. saveToCoreData.isPreset = true
  366. saveToCoreData.enabled = true
  367. saveToCoreData.hbt = hbt
  368. saveToCoreData.date = Date()
  369. saveToCoreData.duration = durationTT as NSDecimalNumber
  370. do {
  371. guard self.coredataContext.hasChanges else { return }
  372. try self.coredataContext.save()
  373. } catch {
  374. print(error.localizedDescription)
  375. }
  376. }
  377. }
  378. }
  379. func enactPreset(id: String) {
  380. if var preset = presetsTT.first(where: { $0.id == id }) {
  381. preset.createdAt = Date()
  382. storage.storeTempTargets([preset])
  383. showModal(for: nil)
  384. coredataContext.performAndWait {
  385. var tempTargetsArray = [TempTargetsSlider]()
  386. let requestTempTargets = TempTargetsSlider.fetchRequest() as NSFetchRequest<TempTargetsSlider>
  387. let sortTT = NSSortDescriptor(key: "date", ascending: false)
  388. requestTempTargets.sortDescriptors = [sortTT]
  389. try? tempTargetsArray = coredataContext.fetch(requestTempTargets)
  390. let whichID = tempTargetsArray.first(where: { $0.id == id })
  391. if whichID != nil {
  392. let saveToCoreData = TempTargets(context: self.coredataContext)
  393. saveToCoreData.active = true
  394. saveToCoreData.date = Date()
  395. saveToCoreData.hbt = whichID?.hbt ?? 160
  396. // saveToCoreData.id = id
  397. saveToCoreData.startDate = Date()
  398. saveToCoreData.duration = whichID?.duration ?? 0
  399. do {
  400. guard self.coredataContext.hasChanges else { return }
  401. try self.coredataContext.save()
  402. } catch {
  403. print(error.localizedDescription)
  404. }
  405. } else {
  406. let saveToCoreData = TempTargets(context: self.coredataContext)
  407. saveToCoreData.active = false
  408. saveToCoreData.date = Date()
  409. do {
  410. guard self.coredataContext.hasChanges else { return }
  411. try self.coredataContext.save()
  412. } catch {
  413. print(error.localizedDescription)
  414. }
  415. }
  416. }
  417. }
  418. }
  419. func removePreset(id: String) {
  420. presetsTT = presetsTT.filter { $0.id != id }
  421. storage.storePresets(presetsTT)
  422. }
  423. func computeTarget() -> Decimal {
  424. var ratio = Decimal(percentageTT / 100)
  425. let c = Decimal(hbt - 100)
  426. var target = (c / ratio) - c + 100
  427. if c * (c + target - 100) <= 0 {
  428. ratio = maxValue
  429. target = (c / ratio) - c + 100
  430. }
  431. return Decimal(Double(target))
  432. }
  433. }
  434. }