Skip to content

Commit 58e6a2a

Browse files
authored
LOOP-4752 Integrate stateless algorithm into Loop (#606)
* Start work on new LoopDataManager using stateless algorithm * Fetching data for new ldm * LoopDosingManager * Fix method parameter names * LoopDosingManager handling automatic dosing * Consolidating presets management into TemporaryPresetsManager * Presets consolidation * Reorg back to LoopDataManager * Main status table view updates * Bolus view fetching algo input * Fix iob graph issue * Get active carb values for graph time frame * Notify on update of settings * Fix carb display and edit * Update active insulin and active carbs in bolus entry view * Restore active preset, and add note about premeal. Always confirm override deactivation. * Refactoring * Mocking for simplifying DeviceDataManagerTests * Fixing more tests * LoopDataManager tests all passing * Fixing tests * Meal detection manager tests * Update remote recommendations * TemporaryPresetsManagerTests * BolusEntryView use recommendManualBolus * Add tests for max iob * Cleanup * Cleanup * LoopSettingsTests were just overrides tests, and have been moved to TemporaryPresetsManagerTests * Get active insulin from loop display state * Update from PR feedback * Assert DeviceDataManager triggers alert upload * Remove unused method * Guard against missing glucose
1 parent 62b673b commit 58e6a2a

File tree

122 files changed

+6065
-15175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+6065
-15175
lines changed

Common/Models/LoopSettingsUserInfo.swift

Lines changed: 80 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,67 @@
66
//
77

88
import LoopCore
9+
import LoopKit
910

11+
struct LoopSettingsUserInfo: Equatable {
12+
var loopSettings: LoopSettings
13+
var scheduleOverride: TemporaryScheduleOverride?
14+
var preMealOverride: TemporaryScheduleOverride?
15+
16+
public mutating func enablePreMealOverride(at date: Date = Date(), for duration: TimeInterval) {
17+
preMealOverride = makePreMealOverride(beginningAt: date, for: duration)
18+
}
19+
20+
private func makePreMealOverride(beginningAt date: Date = Date(), for duration: TimeInterval) -> TemporaryScheduleOverride? {
21+
guard let preMealTargetRange = loopSettings.preMealTargetRange else {
22+
return nil
23+
}
24+
return TemporaryScheduleOverride(
25+
context: .preMeal,
26+
settings: TemporaryScheduleOverrideSettings(targetRange: preMealTargetRange),
27+
startDate: date,
28+
duration: .finite(duration),
29+
enactTrigger: .local,
30+
syncIdentifier: UUID()
31+
)
32+
}
33+
34+
public mutating func clearOverride(matching context: TemporaryScheduleOverride.Context? = nil) {
35+
if context == .preMeal {
36+
preMealOverride = nil
37+
return
38+
}
39+
40+
guard let scheduleOverride = scheduleOverride else { return }
41+
42+
if let context = context {
43+
if scheduleOverride.context == context {
44+
self.scheduleOverride = nil
45+
}
46+
} else {
47+
self.scheduleOverride = nil
48+
}
49+
}
50+
51+
public func nonPreMealOverrideEnabled(at date: Date = Date()) -> Bool {
52+
return scheduleOverride?.isActive(at: date) == true
53+
}
54+
55+
public mutating func legacyWorkoutOverride(beginningAt date: Date = Date(), for duration: TimeInterval) -> TemporaryScheduleOverride? {
56+
guard let legacyWorkoutTargetRange = loopSettings.legacyWorkoutTargetRange else {
57+
return nil
58+
}
59+
60+
return TemporaryScheduleOverride(
61+
context: .legacyWorkout,
62+
settings: TemporaryScheduleOverrideSettings(targetRange: legacyWorkoutTargetRange),
63+
startDate: date,
64+
duration: duration.isInfinite ? .indefinite : .finite(duration),
65+
enactTrigger: .local,
66+
syncIdentifier: UUID()
67+
)
68+
}
1069

11-
struct LoopSettingsUserInfo {
12-
let settings: LoopSettings
1370
}
1471

1572

@@ -23,19 +80,36 @@ extension LoopSettingsUserInfo: RawRepresentable {
2380
guard rawValue["v"] as? Int == LoopSettingsUserInfo.version,
2481
rawValue["name"] as? String == LoopSettingsUserInfo.name,
2582
let settingsRaw = rawValue["s"] as? LoopSettings.RawValue,
26-
let settings = LoopSettings(rawValue: settingsRaw)
83+
let loopSettings = LoopSettings(rawValue: settingsRaw)
2784
else {
2885
return nil
2986
}
3087

31-
self.settings = settings
88+
self.loopSettings = loopSettings
89+
90+
if let rawScheduleOverride = rawValue["o"] as? TemporaryScheduleOverride.RawValue {
91+
self.scheduleOverride = TemporaryScheduleOverride(rawValue: rawScheduleOverride)
92+
} else {
93+
self.scheduleOverride = nil
94+
}
95+
96+
if let rawPreMealOverride = rawValue["p"] as? TemporaryScheduleOverride.RawValue {
97+
self.preMealOverride = TemporaryScheduleOverride(rawValue: rawPreMealOverride)
98+
} else {
99+
self.preMealOverride = nil
100+
}
32101
}
33102

34103
var rawValue: RawValue {
35-
return [
104+
var raw: RawValue = [
36105
"v": LoopSettingsUserInfo.version,
37106
"name": LoopSettingsUserInfo.name,
38-
"s": settings.rawValue
107+
"s": loopSettings.rawValue
39108
]
109+
110+
raw["o"] = scheduleOverride?.rawValue
111+
raw["p"] = preMealOverride?.rawValue
112+
113+
return raw
40114
}
41115
}

Loop.xcodeproj/project.pbxproj

Lines changed: 79 additions & 209 deletions
Large diffs are not rendered by default.

Loop/AppDelegate.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,14 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider {
2222

2323
setenv("CFNETWORK_DIAGNOSTICS", "3", 1)
2424

25-
loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions)
26-
loopAppManager.launch()
27-
return loopAppManager.isLaunchComplete
25+
// Avoid doing full initialization when running tests
26+
if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil {
27+
loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions)
28+
loopAppManager.launch()
29+
return loopAppManager.isLaunchComplete
30+
} else {
31+
return true
32+
}
2833
}
2934

3035
// MARK: - UIApplicationDelegate - Life Cycle

Loop/Extensions/BasalDeliveryState.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import LoopKit
1010
import LoopCore
1111

1212
extension PumpManagerStatus.BasalDeliveryState {
13-
func getNetBasal(basalSchedule: BasalRateSchedule, settings: LoopSettings) -> NetBasal? {
13+
func getNetBasal(basalSchedule: BasalRateSchedule, maximumBasalRatePerHour: Double?) -> NetBasal? {
1414
func scheduledBasal(for date: Date) -> AbsoluteScheduleValue<Double>? {
1515
return basalSchedule.between(start: date, end: date).first
1616
}
@@ -20,7 +20,7 @@ extension PumpManagerStatus.BasalDeliveryState {
2020
if let scheduledBasal = scheduledBasal(for: dose.startDate) {
2121
return NetBasal(
2222
lastTempBasal: dose,
23-
maxBasal: settings.maximumBasalRatePerHour,
23+
maxBasal: maximumBasalRatePerHour,
2424
scheduledBasal: scheduledBasal
2525
)
2626
} else {
@@ -30,7 +30,7 @@ extension PumpManagerStatus.BasalDeliveryState {
3030
if let scheduledBasal = scheduledBasal(for: date) {
3131
return NetBasal(
3232
suspendedAt: date,
33-
maxBasal: settings.maximumBasalRatePerHour,
33+
maxBasal: maximumBasalRatePerHour,
3434
scheduledBasal: scheduledBasal
3535
)
3636
} else {

Loop/Extensions/DeviceDataManager+BolusEntryViewModelDelegate.swift

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

Loop/Extensions/DeviceDataManager+DeviceStatus.swift

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,16 @@ extension DeviceDataManager {
4141
} else if pumpManager == nil {
4242
return DeviceDataManager.addPumpStatusHighlight
4343
} else {
44-
return pumpManager?.pumpStatusHighlight
44+
return (pumpManager as? PumpManagerUI)?.pumpStatusHighlight
4545
}
4646
}
4747

4848
var pumpStatusBadge: DeviceStatusBadge? {
49-
return pumpManager?.pumpStatusBadge
49+
return (pumpManager as? PumpManagerUI)?.pumpStatusBadge
5050
}
5151

5252
var pumpLifecycleProgress: DeviceLifecycleProgress? {
53-
return pumpManager?.pumpLifecycleProgress
53+
return (pumpManager as? PumpManagerUI)?.pumpLifecycleProgress
5454
}
5555

5656
static var resumeOnboardingStatusHighlight: ResumeOnboardingStatusHighlight {
@@ -104,18 +104,12 @@ extension DeviceDataManager {
104104
let action = pumpManagerHUDProvider.didTapOnHUDView(view, allowDebugFeatures: FeatureFlags.allowDebugFeatures)
105105
{
106106
return action
107-
} else if let pumpManager = pumpManager {
107+
} else if let pumpManager = pumpManager as? PumpManagerUI {
108108
return .presentViewController(pumpManager.settingsViewController(bluetoothProvider: bluetoothProvider, colorPalette: .default, allowDebugFeatures: FeatureFlags.allowDebugFeatures, allowedInsulinTypes: allowedInsulinTypes))
109109
} else {
110110
return .setupNewPump
111111
}
112-
}
113-
114-
var isGlucoseValueStale: Bool {
115-
guard let latestGlucoseDataDate = glucoseStore.latestGlucose?.startDate else { return true }
116-
117-
return Date().timeIntervalSince(latestGlucoseDataDate) > LoopAlgorithm.inputDataRecencyInterval
118-
}
112+
}
119113
}
120114

121115
// MARK: - BluetoothState

Loop/Extensions/DeviceDataManager+SimpleBolusViewModelDelegate.swift

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

Loop/Extensions/SettingsStore+SimulatedCoreData.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,7 @@ fileprivate extension StoredSettings {
154154
glucoseTargetRangeSchedule: glucoseTargetRangeSchedule,
155155
preMealTargetRange: DoubleRange(minValue: 80.0, maxValue: 90.0).quantityRange(for: .milligramsPerDeciliter),
156156
workoutTargetRange: DoubleRange(minValue: 150.0, maxValue: 160.0).quantityRange(for: .milligramsPerDeciliter),
157-
overridePresets: nil,
158-
scheduleOverride: nil,
159-
preMealOverride: preMealOverride,
157+
overridePresets: [],
160158
maximumBasalRatePerHour: 3.5,
161159
maximumBolus: 10.0,
162160
suspendThreshold: GlucoseThreshold(unit: .milligramsPerDeciliter, value: 75.0),

Loop/Extensions/UIDevice+Loop.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extension UIDevice {
3737
}
3838

3939
extension UIDevice {
40-
func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) {
40+
func generateDiagnosticReport() -> String {
4141
var report: [String] = [
4242
"## Device",
4343
"",
@@ -53,7 +53,7 @@ extension UIDevice {
5353
"* batteryState: \(String(describing: batteryState))",
5454
]
5555
}
56-
completion(report.joined(separator: "\n"))
56+
return report.joined(separator: "\n")
5757
}
5858
}
5959

0 commit comments

Comments
 (0)