From a163ab9527402b9f913a919c95455e9e1aa7299f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Sun, 1 Nov 2026 19:22:22 +0100 Subject: [PATCH] Base the Loop predictive low alarm on the full forecast and remove the Download Prediction setting --- LoopFollow/Charts/BGChartStubs.swift | 2 ++ .../Controllers/Nightscout/DeviceStatusLoop.swift | 6 +++++- LoopFollow/Settings/AdvancedSettingsView.swift | 1 - .../Settings/AdvancedSettingsViewModel.swift | 7 ------- LoopFollow/Storage/Storage.swift | 1 - LoopFollow/Task/AlarmTask.swift | 15 +++++++++------ .../ViewControllers/MainViewController.swift | 2 ++ 7 files changed, 18 insertions(+), 16 deletions(-) diff --git a/LoopFollow/Charts/BGChartStubs.swift b/LoopFollow/Charts/BGChartStubs.swift index 700821a66..8ecab09dc 100644 --- a/LoopFollow/Charts/BGChartStubs.swift +++ b/LoopFollow/Charts/BGChartStubs.swift @@ -90,6 +90,8 @@ extension MainViewController { // Removes the Loop forecast line. Used when the active system switches away from Loop. func clearLoopPredictionGraph() { + loopPredBGs = nil + loopPredUpdatedTime = nil guard !predictionData.isEmpty else { return } predictionData.removeAll() updatePredictionGraph() diff --git a/LoopFollow/Controllers/Nightscout/DeviceStatusLoop.swift b/LoopFollow/Controllers/Nightscout/DeviceStatusLoop.swift index 93940397c..5e4449c64 100644 --- a/LoopFollow/Controllers/Nightscout/DeviceStatusLoop.swift +++ b/LoopFollow/Controllers/Nightscout/DeviceStatusLoop.swift @@ -73,7 +73,9 @@ extension MainViewController { { Observable.shared.predictionText.value = Localizer.toDisplayUnits(String(Int(round(lastPrediction)))) Observable.shared.predictionColor.value = .purple - if Storage.shared.downloadPrediction.value, previousLastLoopTime < lastLoopTime || predictionData.isEmpty { + loopPredBGs = prediction + loopPredUpdatedTime = lastLoopTime + if previousLastLoopTime < lastLoopTime || predictionData.isEmpty { predictionData.removeAll() var predictionTime = lastLoopTime let toLoad = Int(Storage.shared.predictionToLoad.value * 12) @@ -101,6 +103,8 @@ extension MainViewController { updatePredictionGraph() } } else { + loopPredBGs = nil + loopPredUpdatedTime = nil predictionData.removeAll() infoManager.clearInfoData(type: .minMax) updatePredictionGraph() diff --git a/LoopFollow/Settings/AdvancedSettingsView.swift b/LoopFollow/Settings/AdvancedSettingsView.swift index 9665df882..9f3c00fee 100644 --- a/LoopFollow/Settings/AdvancedSettingsView.swift +++ b/LoopFollow/Settings/AdvancedSettingsView.swift @@ -10,7 +10,6 @@ struct AdvancedSettingsView: View { Form { Section(header: Text("Advanced Settings")) { Toggle("Download Treatments", isOn: $viewModel.downloadTreatments) - Toggle("Download Prediction", isOn: $viewModel.downloadPrediction) Toggle("Graph Basal", isOn: $viewModel.graphBasal) Toggle("Graph Bolus", isOn: $viewModel.graphBolus) Toggle("Graph Carbs", isOn: $viewModel.graphCarbs) diff --git a/LoopFollow/Settings/AdvancedSettingsViewModel.swift b/LoopFollow/Settings/AdvancedSettingsViewModel.swift index 078e62288..38d68b993 100644 --- a/LoopFollow/Settings/AdvancedSettingsViewModel.swift +++ b/LoopFollow/Settings/AdvancedSettingsViewModel.swift @@ -10,12 +10,6 @@ class AdvancedSettingsViewModel: ObservableObject { } } - @Published var downloadPrediction: Bool { - didSet { - Storage.shared.downloadPrediction.value = downloadPrediction - } - } - @Published var graphBasal: Bool { didSet { Storage.shared.graphBasal.value = graphBasal @@ -58,7 +52,6 @@ class AdvancedSettingsViewModel: ObservableObject { init() { downloadTreatments = Storage.shared.downloadTreatments.value - downloadPrediction = Storage.shared.downloadPrediction.value graphBasal = Storage.shared.graphBasal.value graphBolus = Storage.shared.graphBolus.value graphCarbs = Storage.shared.graphCarbs.value diff --git a/LoopFollow/Storage/Storage.swift b/LoopFollow/Storage/Storage.swift index 5417df992..4f533740a 100644 --- a/LoopFollow/Storage/Storage.swift +++ b/LoopFollow/Storage/Storage.swift @@ -183,7 +183,6 @@ class Storage { // MARK: - Advanced settings --------------------------------------------------- var downloadTreatments = StorageValue(key: "downloadTreatments", defaultValue: true) - var downloadPrediction = StorageValue(key: "downloadPrediction", defaultValue: true) var graphOtherTreatments = StorageValue(key: "graphOtherTreatments", defaultValue: true) var graphBasal = StorageValue(key: "graphBasal", defaultValue: true) var graphBolus = StorageValue(key: "graphBolus", defaultValue: true) diff --git a/LoopFollow/Task/AlarmTask.swift b/LoopFollow/Task/AlarmTask.swift index 53bea67ba..d74289ecf 100644 --- a/LoopFollow/Task/AlarmTask.swift +++ b/LoopFollow/Task/AlarmTask.swift @@ -79,14 +79,17 @@ extension MainViewController { /// Builds the forward glucose series the low alarm looks ahead in, /// oldest .. newest at 5-minute spacing. /// - /// Loop reports a single forecast, already stored in `predictionData`. Trio - /// reports four forecasts, collapsed into the lowest value per point in time - /// by `lowestForecast(forecasts:start:cap:)`. + /// Both series come from the full forecast as uploaded, independent of the + /// graph settings. Loop reports a single forecast; Trio reports four, + /// collapsed into the lowest value per point in time by + /// `lowestForecast(forecasts:start:cap:)`. func alarmPredictionData() -> [GlucoseValue] { if Storage.shared.device.value == "Loop" { - return predictionData - .prefix(MainViewController.alarmForecastPointCap) - .map { GlucoseValue(sgv: $0.sgv, date: Date(timeIntervalSince1970: $0.date)) } + guard let predBGs = loopPredBGs else { return [] } + return MainViewController.lowestForecast( + forecasts: [predBGs], + start: loopPredUpdatedTime ?? Date().timeIntervalSince1970 + ) } guard let predBGs = openAPSPredBGs else { return [] } diff --git a/LoopFollow/ViewControllers/MainViewController.swift b/LoopFollow/ViewControllers/MainViewController.swift index dce0b6611..b4af72f72 100644 --- a/LoopFollow/ViewControllers/MainViewController.swift +++ b/LoopFollow/ViewControllers/MainViewController.swift @@ -91,6 +91,8 @@ class MainViewController: UIViewController, UNUserNotificationCenterDelegate { var iobPredictionData: [ShareGlucoseData] = [] var cobPredictionData: [ShareGlucoseData] = [] var uamPredictionData: [ShareGlucoseData] = [] + var loopPredBGs: [Double]? + var loopPredUpdatedTime: TimeInterval? var openAPSPredBGs: [String: [Double]]? var openAPSPredUpdatedTime: TimeInterval? var bgCheckData: [ShareGlucoseData] = []