Skip to content

Commit eeeb046

Browse files
authored
[LOOP-928] Enforce deliverable increments on watch (#137)
* [LOOP-928] Enforce deliverable volumes on watch * Fix up userInfoTransfer error handling
1 parent 6460085 commit eeeb046

File tree

12 files changed

+227
-95
lines changed

12 files changed

+227
-95
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//
2+
// SupportedBolusVolumesUserInfo.swift
3+
// Loop
4+
//
5+
// Created by Michael Pangburn on 6/30/20.
6+
// Copyright © 2020 LoopKit Authors. All rights reserved.
7+
//
8+
9+
struct SupportedBolusVolumesUserInfo {
10+
var supportedBolusVolumes: [Double]
11+
}
12+
13+
extension SupportedBolusVolumesUserInfo: RawRepresentable {
14+
typealias RawValue = [String: Any]
15+
16+
private enum Key: String {
17+
case version = "v"
18+
case name = "name"
19+
case supportedBolusVolumes = "sbv"
20+
}
21+
22+
static let name = "SupportedBolusVolumesUserInfo"
23+
static let version = 1
24+
25+
init?(rawValue: RawValue) {
26+
guard
27+
rawValue[Key.version.rawValue] as? Int == Self.version,
28+
rawValue[Key.name.rawValue] as? String == Self.name,
29+
let supportedBolusVolumes = rawValue[Key.supportedBolusVolumes.rawValue] as? [Double]
30+
else {
31+
return nil
32+
}
33+
34+
self.init(supportedBolusVolumes: supportedBolusVolumes)
35+
}
36+
37+
var rawValue: RawValue {
38+
[
39+
Key.version.rawValue: Self.version,
40+
Key.name.rawValue: Self.name,
41+
Key.supportedBolusVolumes.rawValue: supportedBolusVolumes
42+
]
43+
}
44+
}

Loop.xcodeproj/project.pbxproj

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@
8888
43511CE221FD80E400566C63 /* RetrospectiveCorrection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43511CDF21FD80E400566C63 /* RetrospectiveCorrection.swift */; };
8989
43511CE321FD80E400566C63 /* StandardRetrospectiveCorrection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43511CE021FD80E400566C63 /* StandardRetrospectiveCorrection.swift */; };
9090
43511CEE220FC61700566C63 /* HUDRowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43511CED220FC61700566C63 /* HUDRowController.swift */; };
91-
43517915230A07100072ECC0 /* NumberFormatter+WatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43517914230A07100072ECC0 /* NumberFormatter+WatchApp.swift */; };
9291
43517917230A0E1A0072ECC0 /* WKInterfaceLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43517916230A0E1A0072ECC0 /* WKInterfaceLabel.swift */; };
9392
435400341C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; };
9493
435400351C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 435400331C9F878D00D5819C /* SetBolusUserInfo.swift */; };
@@ -363,6 +362,8 @@
363362
898ECA69218ABDA9001E9D35 /* CLKTextProvider+Compound.m in Sources */ = {isa = PBXBuildFile; fileRef = 898ECA67218ABDA8001E9D35 /* CLKTextProvider+Compound.m */; };
364363
899012C3246F442F007B88BA /* CorrectionRangeOverridesEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899012C2246F442F007B88BA /* CorrectionRangeOverridesEditor.swift */; };
365364
899433B823FE129800FA4BEA /* OverrideBadgeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 899433B723FE129700FA4BEA /* OverrideBadgeView.swift */; };
365+
89A1B66E24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A1B66D24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift */; };
366+
89A1B66F24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A1B66D24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift */; };
366367
89A605E324327DFE009C1096 /* CarbAmountInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A605E224327DFE009C1096 /* CarbAmountInput.swift */; };
367368
89A605E524327F45009C1096 /* DoseVolumeInput.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A605E424327F45009C1096 /* DoseVolumeInput.swift */; };
368369
89A605E72432860C009C1096 /* PeriodicPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89A605E62432860C009C1096 /* PeriodicPublisher.swift */; };
@@ -391,6 +392,7 @@
391392
89F9119224358E2B00ECCAF3 /* CarbEntryInputMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9119124358E2B00ECCAF3 /* CarbEntryInputMode.swift */; };
392393
89F9119424358E4500ECCAF3 /* CarbAbsorptionTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9119324358E4500ECCAF3 /* CarbAbsorptionTime.swift */; };
393394
89F9119624358E6900ECCAF3 /* BolusPickerValues.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F9119524358E6900ECCAF3 /* BolusPickerValues.swift */; };
395+
89FE21AD24AC57E30033F501 /* Collection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FE21AC24AC57E30033F501 /* Collection.swift */; };
394396
A92E557E2464DFFD00DB93BB /* DosingDecisionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = A92E557D2464DFFD00DB93BB /* DosingDecisionStore.swift */; };
395397
A966152623EA5A26005D8B29 /* DefaultAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A966152423EA5A25005D8B29 /* DefaultAssets.xcassets */; };
396398
A966152723EA5A26005D8B29 /* DerivedAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A966152523EA5A25005D8B29 /* DerivedAssets.xcassets */; };
@@ -699,7 +701,6 @@
699701
43511CDF21FD80E400566C63 /* RetrospectiveCorrection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RetrospectiveCorrection.swift; sourceTree = "<group>"; };
700702
43511CE021FD80E400566C63 /* StandardRetrospectiveCorrection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StandardRetrospectiveCorrection.swift; sourceTree = "<group>"; };
701703
43511CED220FC61700566C63 /* HUDRowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDRowController.swift; sourceTree = "<group>"; };
702-
43517914230A07100072ECC0 /* NumberFormatter+WatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+WatchApp.swift"; sourceTree = "<group>"; };
703704
43517916230A0E1A0072ECC0 /* WKInterfaceLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WKInterfaceLabel.swift; sourceTree = "<group>"; };
704705
435400331C9F878D00D5819C /* SetBolusUserInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetBolusUserInfo.swift; sourceTree = "<group>"; };
705706
435CB6221F37967800C320C7 /* InsulinModelSettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InsulinModelSettingsViewController.swift; sourceTree = "<group>"; };
@@ -1091,6 +1092,7 @@
10911092
898ECA68218ABDA9001E9D35 /* CLKTextProvider+Compound.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CLKTextProvider+Compound.h"; sourceTree = "<group>"; };
10921093
899012C2246F442F007B88BA /* CorrectionRangeOverridesEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CorrectionRangeOverridesEditor.swift; sourceTree = "<group>"; };
10931094
899433B723FE129700FA4BEA /* OverrideBadgeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideBadgeView.swift; sourceTree = "<group>"; };
1095+
89A1B66D24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportedBolusVolumesUserInfo.swift; sourceTree = "<group>"; };
10941096
89A605E224327DFE009C1096 /* CarbAmountInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbAmountInput.swift; sourceTree = "<group>"; };
10951097
89A605E424327F45009C1096 /* DoseVolumeInput.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoseVolumeInput.swift; sourceTree = "<group>"; };
10961098
89A605E62432860C009C1096 /* PeriodicPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeriodicPublisher.swift; sourceTree = "<group>"; };
@@ -1117,6 +1119,7 @@
11171119
89F9119124358E2B00ECCAF3 /* CarbEntryInputMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbEntryInputMode.swift; sourceTree = "<group>"; };
11181120
89F9119324358E4500ECCAF3 /* CarbAbsorptionTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbAbsorptionTime.swift; sourceTree = "<group>"; };
11191121
89F9119524358E6900ECCAF3 /* BolusPickerValues.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusPickerValues.swift; sourceTree = "<group>"; };
1122+
89FE21AC24AC57E30033F501 /* Collection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Collection.swift; sourceTree = "<group>"; };
11201123
A92E557D2464DFFD00DB93BB /* DosingDecisionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = DosingDecisionStore.swift; path = ../Stores/DosingDecisionStore.swift; sourceTree = "<group>"; };
11211124
A951C5FF23E8AB51003E26DC /* Version.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Version.xcconfig; sourceTree = "<group>"; };
11221125
A966152423EA5A25005D8B29 /* DefaultAssets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = DefaultAssets.xcassets; sourceTree = "<group>"; };
@@ -1356,18 +1359,18 @@
13561359
4328E01F1CFBE2B100E199AA /* Extensions */ = {
13571360
isa = PBXGroup;
13581361
children = (
1362+
898ECA68218ABDA9001E9D35 /* CLKTextProvider+Compound.h */,
1363+
898ECA66218ABDA8001E9D35 /* WatchApp Extension-Bridging-Header.h */,
1364+
898ECA67218ABDA8001E9D35 /* CLKTextProvider+Compound.m */,
13591365
4344629120A7C19800C4BE6F /* ButtonGroup.swift */,
13601366
898ECA64218ABD9A001E9D35 /* CGRect.swift */,
13611367
4328E0221CFBE2C500E199AA /* CLKComplicationTemplate.swift */,
1362-
898ECA68218ABDA9001E9D35 /* CLKTextProvider+Compound.h */,
1363-
898ECA67218ABDA8001E9D35 /* CLKTextProvider+Compound.m */,
1368+
89FE21AC24AC57E30033F501 /* Collection.swift */,
13641369
89E08FCB242E790C000D719B /* Comparable.swift */,
13651370
4F7E8AC420E2AB9600AEA65E /* Date.swift */,
13661371
43785E952120E4010057DED1 /* INRelevantShortcutStore+Loop.swift */,
13671372
4328E0231CFBE2C500E199AA /* NSUserDefaults+WatchApp.swift */,
1368-
43517914230A07100072ECC0 /* NumberFormatter+WatchApp.swift */,
13691373
4328E0241CFBE2C500E199AA /* UIColor.swift */,
1370-
898ECA66218ABDA8001E9D35 /* WatchApp Extension-Bridging-Header.h */,
13711374
4F2C15801E0495B200E160D4 /* WatchContext+WatchApp.swift */,
13721375
43CB2B2A1D924D450079823D /* WCSession.swift */,
13731376
4328E0251CFBE2C500E199AA /* WKAlertAction.swift */,
@@ -1925,14 +1928,15 @@
19251928
89F9119324358E4500ECCAF3 /* CarbAbsorptionTime.swift */,
19261929
4F11D3BF20DCBEEC006E072C /* GlucoseBackfillRequestUserInfo.swift */,
19271930
4372E48F213CFCE70068E043 /* LoopSettingsUserInfo.swift */,
1931+
43C3B6F620BBCAA30026CAFA /* PumpManager.swift */,
1932+
C1FB428E217921D600FAB378 /* PumpManagerUI.swift */,
19281933
435400331C9F878D00D5819C /* SetBolusUserInfo.swift */,
19291934
4F70C2111DE900EA006380B7 /* StatusExtensionContext.swift */,
1935+
89A1B66D24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift */,
19301936
4FF4D0FF1E18374700846527 /* WatchContext.swift */,
1937+
C1201E2B23ECDBD0002DA84A /* WatchContextRequestUserInfo.swift */,
19311938
4F11D3C120DD80B3006E072C /* WatchHistoricalGlucose.swift */,
19321939
4F7E8AC620E2AC0300AEA65E /* WatchPredictedGlucose.swift */,
1933-
43C3B6F620BBCAA30026CAFA /* PumpManager.swift */,
1934-
C1FB428E217921D600FAB378 /* PumpManagerUI.swift */,
1935-
C1201E2B23ECDBD0002DA84A /* WatchContextRequestUserInfo.swift */,
19361940
);
19371941
path = Models;
19381942
sourceTree = "<group>";
@@ -2961,6 +2965,7 @@
29612965
A999D40824663D6D004C89D4 /* SetBolusError.swift in Sources */,
29622966
8968B1122408B3520074BB48 /* UIFont.swift in Sources */,
29632967
438D42FB1D7D11A4003244B0 /* PredictionInputEffectTableViewCell.swift in Sources */,
2968+
89A1B66E24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift in Sources */,
29642969
432E73CB1D24B3D6009AD15D /* RemoteDataServicesManager.swift in Sources */,
29652970
43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */,
29662971
895F37F124A137D0000CCB42 /* DeliveryLimitsEditor.swift in Sources */,
@@ -2978,8 +2983,8 @@
29782983
4F2C15741E0209F500E160D4 /* NSTimeInterval.swift in Sources */,
29792984
89F9119224358E2B00ECCAF3 /* CarbEntryInputMode.swift in Sources */,
29802985
4FF4D1011E18375000846527 /* WatchContext.swift in Sources */,
2986+
89FE21AD24AC57E30033F501 /* Collection.swift in Sources */,
29812987
898ECA63218ABD21001E9D35 /* ComplicationChartManager.swift in Sources */,
2982-
43517915230A07100072ECC0 /* NumberFormatter+WatchApp.swift in Sources */,
29832988
43A9438A1B926B7B0051FA24 /* NotificationController.swift in Sources */,
29842989
439A7945211FE23A0041B75F /* NSUserActivity.swift in Sources */,
29852990
43A943881B926B7B0051FA24 /* ExtensionDelegate.swift in Sources */,
@@ -3024,6 +3029,7 @@
30243029
4328E01E1CFBE25F00E199AA /* CarbAndBolusFlowController.swift in Sources */,
30253030
89E08FCC242E790C000D719B /* Comparable.swift in Sources */,
30263031
432CF87520D8AC950066B889 /* NSUserDefaults+WatchApp.swift in Sources */,
3032+
89A1B66F24ABFDF800117AC2 /* SupportedBolusVolumesUserInfo.swift in Sources */,
30273033
43027F0F1DFE0EC900C51989 /* HKUnit.swift in Sources */,
30283034
4344629220A7C19800C4BE6F /* ButtonGroup.swift in Sources */,
30293035
89A605E924328862009C1096 /* Checkmark.swift in Sources */,

Loop/Managers/WatchDataManager.swift

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ final class WatchDataManager: NSObject {
2323
super.init()
2424

2525
NotificationCenter.default.addObserver(self, selector: #selector(updateWatch(_:)), name: .LoopDataUpdated, object: deviceManager.loopManager)
26+
NotificationCenter.default.addObserver(self, selector: #selector(sendSupportedBolusVolumesIfNeeded), name: .PumpManagerChanged, object: deviceManager)
2627

2728
watchSession?.delegate = self
2829
watchSession?.activate()
@@ -39,6 +40,7 @@ final class WatchDataManager: NSObject {
3940
}()
4041

4142
private var lastSentSettings: LoopSettings?
43+
private var lastSentBolusVolumes: [Double]?
4244

4345
@objc private func updateWatch(_ notification: Notification) {
4446
guard
@@ -84,6 +86,32 @@ final class WatchDataManager: NSObject {
8486
session.transferUserInfo(LoopSettingsUserInfo(settings: settings).rawValue)
8587
}
8688

89+
@objc private func sendSupportedBolusVolumesIfNeeded() {
90+
guard
91+
let volumes = deviceManager.pumpManager?.supportedBolusVolumes,
92+
let session = watchSession,
93+
session.isPaired,
94+
session.isWatchAppInstalled
95+
else {
96+
return
97+
}
98+
99+
guard case .activated = session.activationState else {
100+
session.activate()
101+
return
102+
}
103+
104+
guard volumes != lastSentBolusVolumes else {
105+
log.default("Skipping bolus volumes transfer due to no changes")
106+
return
107+
}
108+
109+
lastSentBolusVolumes = volumes
110+
111+
log.default("Transferring supported bolus volumes")
112+
session.transferUserInfo(SupportedBolusVolumesUserInfo(supportedBolusVolumes: volumes).rawValue)
113+
}
114+
87115
private func sendWatchContextIfNeeded() {
88116
guard let session = watchSession, session.isPaired, session.isWatchAppInstalled else {
89117
return
@@ -306,6 +334,7 @@ extension WatchDataManager: WCSessionDelegate {
306334
} else {
307335
sendSettingsIfNeeded()
308336
sendWatchContextIfNeeded()
337+
sendSupportedBolusVolumesIfNeeded()
309338
}
310339
case .inactive, .notActivated:
311340
break
@@ -320,9 +349,17 @@ extension WatchDataManager: WCSessionDelegate {
320349

321350
// This might be useless, as userInfoTransfer.userInfo seems to be nil when error is non-nil.
322351
switch userInfoTransfer.userInfo["name"] as? String {
323-
case LoopSettingsUserInfo.name?, .none:
352+
case nil:
353+
lastSentSettings = nil
354+
sendSettingsIfNeeded()
355+
lastSentBolusVolumes = nil
356+
sendSupportedBolusVolumesIfNeeded()
357+
case LoopSettingsUserInfo.name:
324358
lastSentSettings = nil
325359
sendSettingsIfNeeded()
360+
case SupportedBolusVolumesUserInfo.name:
361+
lastSentBolusVolumes = nil
362+
sendSupportedBolusVolumesIfNeeded()
326363
default:
327364
break
328365
}
@@ -342,6 +379,7 @@ extension WatchDataManager: WCSessionDelegate {
342379

343380
func sessionReachabilityDidChange(_ session: WCSession) {
344381
sendSettingsIfNeeded()
382+
sendSupportedBolusVolumesIfNeeded()
345383
}
346384
}
347385

WatchApp Extension/ExtensionDelegate.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,15 @@ extension ExtensionDelegate: WCSessionDelegate {
225225
} else {
226226
log.error("Could not decode LoopSettingsUserInfo: %{public}@", userInfo)
227227
}
228+
case SupportedBolusVolumesUserInfo.name:
229+
guard let volumes = SupportedBolusVolumesUserInfo(rawValue: userInfo)?.supportedBolusVolumes else {
230+
log.error("Could not decode SupportedBolusVolumesUserInfo: %{public}@", userInfo)
231+
return
232+
}
233+
234+
DispatchQueue.main.async {
235+
self.loopManager.supportedBolusVolumes = volumes
236+
}
228237
case "WatchContext":
229238
// WatchContext is the only userInfo type without a "name" key. This isn't a great heuristic.
230239
updateContext(userInfo)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//
2+
// Collection.swift
3+
// WatchApp Extension
4+
//
5+
// Created by Michael Pangburn on 6/30/20.
6+
// Copyright © 2020 LoopKit Authors. All rights reserved.
7+
//
8+
9+
extension Collection {
10+
/// Returns a sequence containing adjacent pairs of elements in the ordered collection.
11+
func adjacentPairs() -> Zip2Sequence<Self, SubSequence> {
12+
return zip(self, dropFirst())
13+
}
14+
}

WatchApp Extension/Extensions/NSUserDefaults+WatchApp.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ extension UserDefaults {
1313
private enum Key: String {
1414
case StartOnChartPage = "com.loudnate.Naterade.StartOnChartPage"
1515
case VisibleDuration = "com.loudnate.Naterade.VisibleDuration"
16+
case SupportedBolusVolumes = "com.loopkit.Loop.SupportedBolusVolumes"
1617
}
1718

1819
var startOnChartPage: Bool {
@@ -35,4 +36,17 @@ extension UserDefaults {
3536
set(newValue.rawValue, forKey: Key.VisibleDuration.rawValue)
3637
}
3738
}
39+
40+
var supportedBolusVolumes: [Double]? {
41+
get {
42+
array(forKey: Key.SupportedBolusVolumes.rawValue) as? [Double]
43+
}
44+
set {
45+
guard let newValue = newValue else {
46+
removeObject(forKey: Key.SupportedBolusVolumes.rawValue)
47+
return
48+
}
49+
set(newValue, forKey: Key.SupportedBolusVolumes.rawValue)
50+
}
51+
}
3852
}

WatchApp Extension/Extensions/NumberFormatter+WatchApp.swift

Lines changed: 0 additions & 42 deletions
This file was deleted.

WatchApp Extension/Managers/LoopDataManager.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,15 @@ class LoopDataManager {
3131
}
3232
}
3333

34+
// Main queue only
35+
var supportedBolusVolumes = UserDefaults.standard.supportedBolusVolumes {
36+
didSet {
37+
UserDefaults.standard.supportedBolusVolumes = supportedBolusVolumes
38+
needsDidUpdateContextNotification = true
39+
sendDidUpdateContextNotificationIfNecessary()
40+
}
41+
}
42+
3443
private let log = OSLog(category: "LoopDataManager")
3544

3645
// Main queue only

0 commit comments

Comments
 (0)