OverrideProfilesStateModel.swift 20 KB

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