Skip to content

Commit 2d8e8f9

Browse files
bjorkertmarionbarker
authored andcommitted
Add optional yesterday BG comparison line to main graph (#665)
Adds a Graph Settings toggle (Nightscout only) that overlays yesterday's BG curve on the main graph, time-shifted by 24h so it aligns with the same clock time today. Drawn as a thin dimmed gray line with no dots, purely for comparison. When enabled, one extra day of history is fetched and the overlay is capped to now plus the configured hours of prediction so it never extends further into the future than the prediction line.
1 parent cf69cfa commit 2d8e8f9

5 files changed

Lines changed: 83 additions & 3 deletions

File tree

LoopFollow/Controllers/Graphs.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ enum GraphDataIndex: Int {
4343
case smb = 16
4444
case tempTarget = 17
4545
case predictionCone = 18
46+
case yesterday = 19
4647
}
4748

4849
extension GraphDataIndex {
@@ -67,6 +68,7 @@ extension GraphDataIndex {
6768
case .smb: return "SMB"
6869
case .tempTarget: return "Temp Target"
6970
case .predictionCone: return "Prediction Cone"
71+
case .yesterday: return "Yesterday"
7072
}
7173
}
7274
}
@@ -638,6 +640,16 @@ extension MainViewController {
638640
lineCone.axisDependency = YAxis.AxisDependency.right
639641
data.append(lineCone)
640642

643+
// Dataset 19: Yesterday's BG comparison overlay (thin dimmed gray line, no dots)
644+
let lineYesterday = LineChartDataSet(entries: [ChartDataEntry](), label: "")
645+
lineYesterday.lineWidth = 1.5
646+
lineYesterday.setColor(NSUIColor.systemGray, alpha: 0.4)
647+
lineYesterday.drawCirclesEnabled = false
648+
lineYesterday.drawValuesEnabled = false
649+
lineYesterday.highlightEnabled = false
650+
lineYesterday.axisDependency = YAxis.AxisDependency.right
651+
data.append(lineYesterday)
652+
641653
data.setValueFont(UIFont.systemFont(ofSize: 12))
642654

643655
// Add marker popups for bolus and carbs
@@ -829,6 +841,11 @@ extension MainViewController {
829841
BGChart.data?.notifyDataChanged()
830842
BGChart.notifyDataSetChanged()
831843

844+
// Reflect the yesterday overlay toggle immediately, and reload the BG window
845+
// so the extra day of history is fetched (or dropped) when the toggle changed.
846+
updateYesterdayBGGraph()
847+
TaskScheduler.shared.rescheduleTask(id: .fetchBG, to: Date())
848+
832849
// Re-render prediction display in case display type changed
833850
updateOpenAPSPredictionDisplay()
834851
}
@@ -898,6 +915,8 @@ extension MainViewController {
898915
BGChartFull.data?.notifyDataChanged()
899916
BGChartFull.notifyDataSetChanged()
900917

918+
updateYesterdayBGGraph()
919+
901920
// The initial zoom is a one-shot, relative to the chart's current
902921
// viewport. Skip it until the chart actually has a width — otherwise a
903922
// refresh that lands while the view is loaded but off-screen (e.g. Home
@@ -922,6 +941,32 @@ extension MainViewController {
922941
}
923942
}
924943

944+
// Populates (or clears) the dimmed "yesterday" comparison overlay on the main graph.
945+
// Points in yesterdayBGData are already shifted +24h so they align with today's clock time.
946+
func updateYesterdayBGGraph() {
947+
let dataIndex = GraphDataIndex.yesterday.rawValue
948+
guard let lineData = BGChart.lineData,
949+
dataIndex < lineData.dataSets.count,
950+
let dataSet = lineData.dataSets[dataIndex] as? LineChartDataSet
951+
else {
952+
return
953+
}
954+
955+
dataSet.removeAll(keepingCapacity: false)
956+
957+
if Storage.shared.showYesterdayLine.value {
958+
for entry in yesterdayBGData {
959+
// Clamp the plotted y-value to the same bounds the main BG line uses.
960+
let plottedSgv = Double(min(max(entry.sgv, globalVariables.minDisplayGlucose), globalVariables.maxDisplayGlucose))
961+
dataSet.append(ChartDataEntry(x: entry.date, y: plottedSgv))
962+
}
963+
}
964+
965+
BGChart.data?.dataSets[dataIndex].notifyDataSetChanged()
966+
BGChart.data?.notifyDataChanged()
967+
BGChart.notifyDataSetChanged()
968+
}
969+
925970
func updatePredictionGraph(color: UIColor? = nil) {
926971
let dataIndex = 1
927972
var mainChart = BGChart.lineData!.dataSets[dataIndex] as! LineChartDataSet

LoopFollow/Controllers/Nightscout/BGData.swift

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@ import Foundation
55
import UIKit
66

77
extension MainViewController {
8+
/// Number of days of BG history to request from the source. One extra day is
9+
/// added when the "Show Yesterday's BG" overlay is enabled (Nightscout only),
10+
/// so the overlay can display the same clock time from the day before.
11+
var bgFetchDays: Int {
12+
let extraDay = (Storage.shared.showYesterdayLine.value && IsNightscoutEnabled()) ? 1 : 0
13+
return Storage.shared.downloadDays.value + extraDay
14+
}
15+
816
// Dex Share Web Call
917
func webLoadDexShare() {
1018
// Dexcom Share only returns 24 hrs of data as of now
1119
// Requesting more just for consistency with NS
12-
let graphHours = 24 * Storage.shared.downloadDays.value
20+
let graphHours = 24 * bgFetchDays
1321
let count = graphHours * 12
1422
dexShare?.fetchData(count) { err, result in
1523
if let error = err {
@@ -57,8 +65,8 @@ extension MainViewController {
5765
}
5866

5967
var parameters: [String: String] = [:]
60-
let date = Calendar.current.date(byAdding: .day, value: -1 * Storage.shared.downloadDays.value, to: Date())!
61-
parameters["count"] = "\(Storage.shared.downloadDays.value * globalVariables.maxExpectedUploaders * 24 * 60 / 5)"
68+
let date = Calendar.current.date(byAdding: .day, value: -1 * bgFetchDays, to: Date())!
69+
parameters["count"] = "\(bgFetchDays * globalVariables.maxExpectedUploaders * 24 * 60 / 5)"
6270
parameters["find[date][$gte]"] = "\(Int(date.timeIntervalSince1970 * 1000))"
6371

6472
// Exclude 'cal' entries
@@ -221,6 +229,27 @@ extension MainViewController {
221229
LogManager.shared.log(category: .nightscout,
222230
message: "Graph data updated with \(bgData.count) entries.",
223231
isDebug: true)
232+
233+
// Build the optional "yesterday" comparison overlay. Every fetched reading is
234+
// shifted +24h so it lines up with the same clock time today; the extra day of
235+
// history pulled by bgFetchDays provides the portion that falls inside the
236+
// visible window. The overlay is capped to "now + hours of prediction" so it
237+
// never extends further into the future than the prediction line.
238+
yesterdayBGData.removeAll()
239+
if Storage.shared.showYesterdayLine.value, IsNightscoutEnabled() {
240+
let cutoff = dateTimeUtils.getTimeIntervalNHoursAgo(N: 24 * bgFetchDays)
241+
let futureLimit = dateTimeUtils.getNowTimeIntervalUTC() + Storage.shared.predictionToLoad.value * 3600
242+
for i in 0 ..< data.count {
243+
let reading = data[data.count - 1 - i]
244+
guard reading.date >= cutoff, reading.sgv <= 600 else { continue }
245+
let shiftedDate = reading.date + 24 * 60 * 60
246+
guard shiftedDate <= futureLimit else { continue }
247+
yesterdayBGData.append(ShareGlucoseData(sgv: reading.sgv,
248+
date: shiftedDate,
249+
direction: reading.direction))
250+
}
251+
}
252+
224253
viewUpdateNSBG(sourceName: sourceName)
225254
}
226255

LoopFollow/Settings/GraphSettingsView.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct GraphSettingsView: View {
1212
@ObservedObject private var show30MinLine = Storage.shared.show30MinLine
1313
@ObservedObject private var show90MinLine = Storage.shared.show90MinLine
1414
@ObservedObject private var showMidnightLines = Storage.shared.showMidnightLines
15+
@ObservedObject private var showYesterdayLine = Storage.shared.showYesterdayLine
1516
@ObservedObject private var smallGraphTreatments = Storage.shared.smallGraphTreatments
1617

1718
@ObservedObject private var smallGraphHeight = Storage.shared.smallGraphHeight
@@ -42,6 +43,9 @@ struct GraphSettingsView: View {
4243

4344
Toggle("Show −90 min Line", isOn: $show90MinLine.value)
4445
.onChange(of: show90MinLine.value) { _ in markDirty() }
46+
47+
Toggle("Show Yesterday's BG", isOn: $showYesterdayLine.value)
48+
.onChange(of: showYesterdayLine.value) { _ in markDirty() }
4549
}
4650

4751
Toggle("Show Midnight Lines", isOn: $showMidnightLines.value)

LoopFollow/Storage/Storage.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class Storage {
129129
var show30MinLine = StorageValue<Bool>(key: "show30MinLine", defaultValue: false)
130130
var show90MinLine = StorageValue<Bool>(key: "show90MinLine", defaultValue: false)
131131
var showMidnightLines = StorageValue<Bool>(key: "showMidnightMarkers", defaultValue: false)
132+
var showYesterdayLine = StorageValue<Bool>(key: "showYesterdayLine", defaultValue: false)
132133
var smallGraphTreatments = StorageValue<Bool>(key: "smallGraphTreatments", defaultValue: true)
133134

134135
var smallGraphHeight = StorageValue<Int>(key: "smallGraphHeight", defaultValue: 40)

LoopFollow/ViewControllers/MainViewController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class MainViewController: UIViewController, ChartViewDelegate, UNUserNotificatio
7373
var profileManager = ProfileManager.shared
7474

7575
var bgData: [ShareGlucoseData] = []
76+
var yesterdayBGData: [ShareGlucoseData] = [] // readings already shifted +24h for the comparison overlay
7677
var basalProfile: [basalProfileStruct] = []
7778
var basalData: [basalGraphStruct] = []
7879
var basalScheduleData: [basalGraphStruct] = []

0 commit comments

Comments
 (0)