@@ -44,6 +44,14 @@ final class WatchDataManager: NSObject {
4444 private var lastSentSettings : LoopSettings ?
4545 private var lastSentBolusVolumes : [ Double ] ?
4646
47+ private var contextDosingDecisions : [ Date : BolusDosingDecision ] {
48+ get { lockedContextDosingDecisions. value }
49+ set { lockedContextDosingDecisions. value = newValue }
50+ }
51+ private var lockedContextDosingDecisions : Locked < [ Date : BolusDosingDecision ] > = Locked ( [ : ] )
52+
53+ private let contextDosingDecisionExpirationDuration : TimeInterval = - . minutes ( 5 )
54+
4755 let sleepStore : SleepStore
4856
4957 var lastBedtimeQuery : Date {
@@ -215,6 +223,8 @@ final class WatchDataManager: NSObject {
215223 }
216224
217225 private func createWatchContext( recommendingBolusFor potentialCarbEntry: NewCarbEntry ? = nil , _ completion: @escaping ( _ context: WatchContext ) -> Void ) {
226+ var dosingDecision = BolusDosingDecision ( )
227+
218228 let loopManager = deviceManager. loopManager!
219229
220230 let glucose = deviceManager. glucoseStore. latestGlucose
@@ -223,13 +233,20 @@ final class WatchDataManager: NSObject {
223233
224234 loopManager. getLoopState { ( manager, state) in
225235 let updateGroup = DispatchGroup ( )
236+
237+ let carbsOnBoard = state. carbsOnBoard
238+ let recommendedBolus = state. recommendedBolus
239+
226240 let context = WatchContext ( glucose: glucose, glucoseUnit: self . deviceManager. glucoseStore. preferredUnit)
227241 context. reservoir = reservoir? . unitVolume
228242 context. loopLastRunDate = manager. lastLoopCompleted
229- context. recommendedBolusDose = state . recommendedBolus? . recommendation. amount
230- context. cob = state . carbsOnBoard? . quantity. doubleValue ( for: HKUnit . gram ( ) )
243+ context. recommendedBolusDose = recommendedBolus? . recommendation. amount
244+ context. cob = carbsOnBoard? . quantity. doubleValue ( for: HKUnit . gram ( ) )
231245 context. glucoseTrendRawValue = self . deviceManager. glucoseDisplay ( for: glucose) ? . trendType? . rawValue
232246
247+ dosingDecision. carbsOnBoard = carbsOnBoard
248+ dosingDecision. recommendedBolus = recommendedBolus? . recommendation
249+
233250 context. cgmManagerState = self . deviceManager. cgmManager? . rawValue
234251
235252 if let trend = self . deviceManager. cgmManager? . glucoseDisplay? . trendType {
@@ -238,7 +255,11 @@ final class WatchDataManager: NSObject {
238255
239256 if let potentialCarbEntry = potentialCarbEntry {
240257 context. potentialCarbEntry = potentialCarbEntry
241- context. recommendedBolusDoseConsideringPotentialCarbEntry = try ? state. recommendBolus ( consideringPotentialCarbEntry: potentialCarbEntry, replacingCarbEntry: nil ) ? . amount
258+ if let recommendedBolusDoseConsideringPotentialCarbEntry = try ? state. recommendBolus ( consideringPotentialCarbEntry: potentialCarbEntry, replacingCarbEntry: nil ) {
259+ context. recommendedBolusDoseConsideringPotentialCarbEntry = recommendedBolusDoseConsideringPotentialCarbEntry. amount
260+ dosingDecision. recommendedBolus = recommendedBolusDoseConsideringPotentialCarbEntry
261+ }
262+
242263 }
243264
244265 if let glucose = glucose {
@@ -260,8 +281,10 @@ final class WatchDataManager: NSObject {
260281 switch result {
261282 case . success( let iobValue) :
262283 context. iob = iobValue. value
284+ dosingDecision. insulinOnBoard = iobValue
263285 case . failure:
264286 context. iob = nil
287+ dosingDecision. insulinOnBoard = nil
265288 }
266289 updateGroup. leave ( )
267290 }
@@ -273,12 +296,42 @@ final class WatchDataManager: NSObject {
273296 context. lastNetTempBasalDose = netBasal. rate
274297 }
275298
276- // Drop the first element in predictedGlucose because it is the current glucose
277- if let predictedGlucose = state. predictedGlucoseIncludingPendingInsulin? . dropFirst ( ) , predictedGlucose. count > 0 {
278- context. predictedGlucose = WatchPredictedGlucose ( values: Array ( predictedGlucose) )
299+ if let predictedGlucose = state. predictedGlucoseIncludingPendingInsulin {
300+ dosingDecision. predictedGlucoseIncludingPendingInsulin = predictedGlucose
301+
302+ // Drop the first element in predictedGlucose because it is the current glucose
303+ let filteredPredictedGlucose = predictedGlucose. dropFirst ( )
304+ if filteredPredictedGlucose. count > 0 {
305+ context. predictedGlucose = WatchPredictedGlucose ( values: Array ( filteredPredictedGlucose) )
306+ }
307+ }
308+
309+ let settings = self . deviceManager. loopManager. settings
310+
311+ var preMealOverride = settings. preMealOverride
312+ if preMealOverride? . hasFinished ( ) == true {
313+ preMealOverride = nil
314+ }
315+
316+ var scheduleOverride = settings. scheduleOverride
317+ if scheduleOverride? . hasFinished ( ) == true {
318+ scheduleOverride = nil
319+ }
320+
321+ dosingDecision. scheduleOverride = preMealOverride ?? scheduleOverride
322+ dosingDecision. glucoseTargetRangeSchedule = settings. glucoseTargetRangeSchedule
323+ if scheduleOverride != nil || preMealOverride != nil {
324+ dosingDecision. glucoseTargetRangeScheduleApplyingOverrideIfActive = settings. glucoseTargetRangeScheduleApplyingOverrideIfActive
325+ } else {
326+ dosingDecision. glucoseTargetRangeScheduleApplyingOverrideIfActive = nil
279327 }
280328
281329 _ = updateGroup. wait ( timeout: . distantFuture)
330+
331+ // Remove any expired context dosing decisions and add new
332+ self . contextDosingDecisions = self . contextDosingDecisions. filter { ( date, _) in date. timeIntervalSinceNow > self . contextDosingDecisionExpirationDuration }
333+ self . contextDosingDecisions [ context. creationDate] = dosingDecision
334+
282335 completion ( context)
283336 }
284337 }
@@ -289,7 +342,17 @@ final class WatchDataManager: NSObject {
289342 return
290343 }
291344
345+ var dosingDecision : BolusDosingDecision
346+ if let contextDate = bolus. contextDate, let contextDosingDecision = contextDosingDecisions [ contextDate] {
347+ dosingDecision = contextDosingDecision
348+ } else {
349+ dosingDecision = BolusDosingDecision ( ) // The user saved without waiting for recommendation (no bolus)
350+ }
351+
292352 func enactBolus( ) {
353+ dosingDecision. requestedBolus = bolus. value
354+ deviceManager. loopManager. storeBolusDosingDecision ( dosingDecision, withDate: bolus. startDate)
355+
293356 guard bolus. value > 0 else {
294357 // Ensure active carbs is updated in the absence of a bolus
295358 sendWatchContextIfNeeded ( )
@@ -309,14 +372,16 @@ final class WatchDataManager: NSObject {
309372 if let carbEntry = bolus. carbEntry {
310373 deviceManager. loopManager. addCarbEntry ( carbEntry) { ( result) in
311374 switch result {
312- case . success:
375+ case . success( let storedCarbEntry) :
376+ dosingDecision. carbEntry = storedCarbEntry
313377 self . deviceManager. analyticsServicesManager. didAddCarbsFromWatch ( )
314378 enactBolus ( )
315379 case . failure( let error) :
316380 self . log. error ( " %{public}@ " , String ( describing: error) )
317381 }
318382 }
319383 } else {
384+ dosingDecision. carbEntry = nil
320385 enactBolus ( )
321386 }
322387 }
0 commit comments