Преглед изворни кода

Add glucose targets to main chart WIP

Deniz Cengiz пре 1 година
родитељ
комит
517a69783f

+ 6 - 2
FreeAPS.xcodeproj/project.pbxproj

@@ -456,6 +456,7 @@
 		DD1745552C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745542C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift */; };
 		DD1745552C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745542C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift */; };
 		DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */; };
 		DD1DB7CC2BECCA1F0048B367 /* BuildDetails.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */; };
 		DD21FCB52C6952AD00AF2C25 /* DecimalPickerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */; };
 		DD21FCB52C6952AD00AF2C25 /* DecimalPickerSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */; };
+		DD2CC85C2D25DA1000445446 /* GlucoseTargetsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD2CC85B2D25D9CE00445446 /* GlucoseTargetsView.swift */; };
 		DD32CF982CC82463003686D6 /* TrioRemoteControl+Bolus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */; };
 		DD32CF982CC82463003686D6 /* TrioRemoteControl+Bolus.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */; };
 		DD32CF9A2CC8247B003686D6 /* TrioRemoteControl+Meal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */; };
 		DD32CF9A2CC8247B003686D6 /* TrioRemoteControl+Meal.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */; };
 		DD32CF9C2CC82499003686D6 /* TrioRemoteControl+TempTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */; };
 		DD32CF9C2CC82499003686D6 /* TrioRemoteControl+TempTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */; };
@@ -483,9 +484,9 @@
 		DD9ECB712CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB6E2CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift */; };
 		DD9ECB712CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB6E2CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift */; };
 		DD9ECB722CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB6F2CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift */; };
 		DD9ECB722CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB6F2CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift */; };
 		DD9ECB742CA9A0C300AA7C45 /* RemoteControlConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB732CA9A0C300AA7C45 /* RemoteControlConfig.swift */; };
 		DD9ECB742CA9A0C300AA7C45 /* RemoteControlConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD9ECB732CA9A0C300AA7C45 /* RemoteControlConfig.swift */; };
+		DDA6E2502D22187500C2988C /* ChartLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E24F2D22187500C2988C /* ChartLegendView.swift */; };
 		DDA6E3202D258E0500C2988C /* OverrideHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E31F2D258E0500C2988C /* OverrideHelpView.swift */; };
 		DDA6E3202D258E0500C2988C /* OverrideHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E31F2D258E0500C2988C /* OverrideHelpView.swift */; };
 		DDA6E3222D25901100C2988C /* TempTargetHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E3212D25901100C2988C /* TempTargetHelpView.swift */; };
 		DDA6E3222D25901100C2988C /* TempTargetHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E3212D25901100C2988C /* TempTargetHelpView.swift */; };
-		DDA6E2502D22187500C2988C /* ChartLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E24F2D22187500C2988C /* ChartLegendView.swift */; };
 		DDA6E3572D25988500C2988C /* ContactImageHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E3562D25988500C2988C /* ContactImageHelpView.swift */; };
 		DDA6E3572D25988500C2988C /* ContactImageHelpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA6E3562D25988500C2988C /* ContactImageHelpView.swift */; };
 		DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC42D05048F00D99BF4 /* ContactImageStorage.swift */; };
 		DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC42D05048F00D99BF4 /* ContactImageStorage.swift */; };
 		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
 		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
@@ -1162,6 +1163,7 @@
 		DD1745542C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsLimitsSettingsRootView.swift; sourceTree = "<group>"; };
 		DD1745542C55CA6C00211FAC /* UnitsLimitsSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitsLimitsSettingsRootView.swift; sourceTree = "<group>"; };
 		DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildDetails.swift; sourceTree = "<group>"; };
 		DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BuildDetails.swift; sourceTree = "<group>"; };
 		DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalPickerSettings.swift; sourceTree = "<group>"; };
 		DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecimalPickerSettings.swift; sourceTree = "<group>"; };
+		DD2CC85B2D25D9CE00445446 /* GlucoseTargetsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseTargetsView.swift; sourceTree = "<group>"; };
 		DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Bolus.swift"; sourceTree = "<group>"; };
 		DD32CF972CC82460003686D6 /* TrioRemoteControl+Bolus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Bolus.swift"; sourceTree = "<group>"; };
 		DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Meal.swift"; sourceTree = "<group>"; };
 		DD32CF992CC8246F003686D6 /* TrioRemoteControl+Meal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Meal.swift"; sourceTree = "<group>"; };
 		DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+TempTarget.swift"; sourceTree = "<group>"; };
 		DD32CF9B2CC82495003686D6 /* TrioRemoteControl+TempTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+TempTarget.swift"; sourceTree = "<group>"; };
@@ -1189,9 +1191,9 @@
 		DD9ECB6E2CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfigProvider.swift; sourceTree = "<group>"; };
 		DD9ECB6E2CA9A0BA00AA7C45 /* RemoteControlConfigProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfigProvider.swift; sourceTree = "<group>"; };
 		DD9ECB6F2CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfigDataFlow.swift; sourceTree = "<group>"; };
 		DD9ECB6F2CA9A0BA00AA7C45 /* RemoteControlConfigDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfigDataFlow.swift; sourceTree = "<group>"; };
 		DD9ECB732CA9A0C300AA7C45 /* RemoteControlConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfig.swift; sourceTree = "<group>"; };
 		DD9ECB732CA9A0C300AA7C45 /* RemoteControlConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteControlConfig.swift; sourceTree = "<group>"; };
+		DDA6E24F2D22187500C2988C /* ChartLegendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartLegendView.swift; sourceTree = "<group>"; };
 		DDA6E31F2D258E0500C2988C /* OverrideHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideHelpView.swift; sourceTree = "<group>"; };
 		DDA6E31F2D258E0500C2988C /* OverrideHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideHelpView.swift; sourceTree = "<group>"; };
 		DDA6E3212D25901100C2988C /* TempTargetHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetHelpView.swift; sourceTree = "<group>"; };
 		DDA6E3212D25901100C2988C /* TempTargetHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetHelpView.swift; sourceTree = "<group>"; };
-		DDA6E24F2D22187500C2988C /* ChartLegendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartLegendView.swift; sourceTree = "<group>"; };
 		DDA6E3562D25988500C2988C /* ContactImageHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImageHelpView.swift; sourceTree = "<group>"; };
 		DDA6E3562D25988500C2988C /* ContactImageHelpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImageHelpView.swift; sourceTree = "<group>"; };
 		DDB37CC22D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		DDB37CC22D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		DDB37CC32D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
 		DDB37CC32D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
@@ -2529,6 +2531,7 @@
 		BDDAF9F12D0055CC00B34E7A /* ChartElements */ = {
 		BDDAF9F12D0055CC00B34E7A /* ChartElements */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				DD2CC85B2D25D9CE00445446 /* GlucoseTargetsView.swift */,
 				BDDAF9EE2D00553E00B34E7A /* SelectionPopoverView.swift */,
 				BDDAF9EE2D00553E00B34E7A /* SelectionPopoverView.swift */,
 				582DF9742C8CDB92001F516D /* GlucoseChartView.swift */,
 				582DF9742C8CDB92001F516D /* GlucoseChartView.swift */,
 				582DF9762C8CDBE7001F516D /* InsulinView.swift */,
 				582DF9762C8CDBE7001F516D /* InsulinView.swift */,
@@ -3657,6 +3660,7 @@
 				BDFD165A2AE40438007F0DDA /* TreatmentsRootView.swift in Sources */,
 				BDFD165A2AE40438007F0DDA /* TreatmentsRootView.swift in Sources */,
 				38E98A2525F52C9300C0CED0 /* IssueReporter.swift in Sources */,
 				38E98A2525F52C9300C0CED0 /* IssueReporter.swift in Sources */,
 				DD1745522C55CA5D00211FAC /* UnitsLimitsSettingsStateModel.swift in Sources */,
 				DD1745522C55CA5D00211FAC /* UnitsLimitsSettingsStateModel.swift in Sources */,
+				DD2CC85C2D25DA1000445446 /* GlucoseTargetsView.swift in Sources */,
 				190EBCC429FF136900BA767D /* UserInterfaceSettingsDataFlow.swift in Sources */,
 				190EBCC429FF136900BA767D /* UserInterfaceSettingsDataFlow.swift in Sources */,
 				5A2325582BFCC168003518CA /* NightscoutConnectView.swift in Sources */,
 				5A2325582BFCC168003518CA /* NightscoutConnectView.swift in Sources */,
 				3811DEB025C9D88300A708ED /* BaseKeychain.swift in Sources */,
 				3811DEB025C9D88300A708ED /* BaseKeychain.swift in Sources */,

+ 4 - 0
FreeAPS/Sources/Models/BGTargets.swift

@@ -6,6 +6,10 @@ struct BGTargets: JSON {
     var targets: [BGTargetEntry]
     var targets: [BGTargetEntry]
 }
 }
 
 
+protocol BGTargetsObserver {
+    func bgTargetsDidChange(_ bgTargets: BGTargets)
+}
+
 extension BGTargets {
 extension BGTargets {
     private enum CodingKeys: String, CodingKey {
     private enum CodingKeys: String, CodingKey {
         case units
         case units

+ 1 - 1
FreeAPS/Sources/Modules/Adjustments/AdjustmentsProvider.swift

@@ -1,6 +1,6 @@
 extension Adjustments {
 extension Adjustments {
     final class Provider: BaseProvider, AdjustmentsProvider {
     final class Provider: BaseProvider, AdjustmentsProvider {
-        func getBGTarget() async -> BGTargets {
+        func getBGTargets() async -> BGTargets {
             await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
             await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])

+ 1 - 1
FreeAPS/Sources/Modules/Adjustments/AdjustmentsStateModel.swift

@@ -105,7 +105,7 @@ extension Adjustments {
             dateFormatter.dateFormat = "HH:mm:ss"
             dateFormatter.dateFormat = "HH:mm:ss"
             dateFormatter.timeZone = TimeZone.current
             dateFormatter.timeZone = TimeZone.current
 
 
-            let bgTargets = await provider.getBGTarget()
+            let bgTargets = await provider.getBGTargets()
             let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
             let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
 
 
             for (index, entry) in entries.enumerated() {
             for (index, entry) in entries.enumerated() {

+ 1 - 1
FreeAPS/Sources/Modules/Home/HomeDataFlow.swift

@@ -13,5 +13,5 @@ protocol HomeProvider: Provider {
     func tempTargets(hours: Int) -> [TempTarget]
     func tempTargets(hours: Int) -> [TempTarget]
     func pumpReservoir() -> Decimal?
     func pumpReservoir() -> Decimal?
     func tempTarget() -> TempTarget?
     func tempTarget() -> TempTarget?
-    func getBGTarget() async -> BGTargets
+    func getBGTargets() -> BGTargets
 }
 }

+ 2 - 2
FreeAPS/Sources/Modules/Home/HomeProvider.swift

@@ -47,8 +47,8 @@ extension Home {
                 ?? [BasalProfileEntry(start: "00:00", minutes: 0, rate: 1)]
                 ?? [BasalProfileEntry(start: "00:00", minutes: 0, rate: 1)]
         }
         }
 
 
-        func getBGTarget() async -> BGTargets {
-            await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
+        func getBGTargets() -> BGTargets {
+            storage.retrieve(OpenAPS.Settings.bgTargets, as: BGTargets.self)
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
         }
         }

+ 18 - 1
FreeAPS/Sources/Modules/Home/HomeStateModel.swift

@@ -25,6 +25,8 @@ extension Home {
         var maxBasal: Decimal = 2
         var maxBasal: Decimal = 2
         var autotunedBasalProfile: [BasalProfileEntry] = []
         var autotunedBasalProfile: [BasalProfileEntry] = []
         var basalProfile: [BasalProfileEntry] = []
         var basalProfile: [BasalProfileEntry] = []
+        var bgTargets = BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
+            ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
         var tempTargets: [TempTarget] = []
         var tempTargets: [TempTarget] = []
         var timerDate = Date()
         var timerDate = Date()
         var closedLoop = false
         var closedLoop = false
@@ -167,6 +169,9 @@ extension Home {
                         self.setupBasalProfile()
                         self.setupBasalProfile()
                     }
                     }
                     group.addTask {
                     group.addTask {
+                        self.setupGlucoseTargets()
+                    }
+                    group.addTask {
                         self.setupReservoir()
                         self.setupReservoir()
                     }
                     }
                     group.addTask {
                     group.addTask {
@@ -269,6 +274,7 @@ extension Home {
             broadcaster.register(PreferencesObserver.self, observer: self)
             broadcaster.register(PreferencesObserver.self, observer: self)
             broadcaster.register(PumpSettingsObserver.self, observer: self)
             broadcaster.register(PumpSettingsObserver.self, observer: self)
             broadcaster.register(BasalProfileObserver.self, observer: self)
             broadcaster.register(BasalProfileObserver.self, observer: self)
+            broadcaster.register(BGTargetsObserver.self, observer: self)
             broadcaster.register(PumpReservoirObserver.self, observer: self)
             broadcaster.register(PumpReservoirObserver.self, observer: self)
             broadcaster.register(PumpDeactivatedObserver.self, observer: self)
             broadcaster.register(PumpDeactivatedObserver.self, observer: self)
 
 
@@ -473,6 +479,13 @@ extension Home {
             }
             }
         }
         }
 
 
+        private func setupGlucoseTargets() {
+            DispatchQueue.main.async { [weak self] in
+                guard let self = self else { return }
+                self.bgTargets = self.provider.getBGTargets()
+            }
+        }
+
         private func setupReservoir() {
         private func setupReservoir() {
             DispatchQueue.main.async { [weak self] in
             DispatchQueue.main.async { [weak self] in
                 guard let self = self else { return }
                 guard let self = self else { return }
@@ -494,7 +507,6 @@ extension Home {
             dateFormatter.dateFormat = "HH:mm"
             dateFormatter.dateFormat = "HH:mm"
             dateFormatter.timeZone = TimeZone.current
             dateFormatter.timeZone = TimeZone.current
 
 
-            let bgTargets = await provider.getBGTarget()
             let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
             let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) }
 
 
             for (index, entry) in entries.enumerated() {
             for (index, entry) in entries.enumerated() {
@@ -548,6 +560,7 @@ extension Home.StateModel:
     PreferencesObserver,
     PreferencesObserver,
     PumpSettingsObserver,
     PumpSettingsObserver,
     BasalProfileObserver,
     BasalProfileObserver,
+    BGTargetsObserver,
     PumpReservoirObserver,
     PumpReservoirObserver,
     PumpTimeZoneObserver,
     PumpTimeZoneObserver,
     PumpDeactivatedObserver
     PumpDeactivatedObserver
@@ -607,6 +620,10 @@ extension Home.StateModel:
         setupBasalProfile()
         setupBasalProfile()
     }
     }
 
 
+    func bgTargetsDidChange(_: BGTargets) {
+        setupGlucoseTargets()
+    }
+
     func pumpReservoirDidChange(_: Decimal) {
     func pumpReservoirDidChange(_: Decimal) {
         setupReservoir()
         setupReservoir()
         displayPumpStatusHighlightMessage()
         displayPumpStatusHighlightMessage()

+ 79 - 0
FreeAPS/Sources/Modules/Home/View/Chart/ChartElements/GlucoseTargetsView.swift

@@ -0,0 +1,79 @@
+import Charts
+import Foundation
+import SwiftUI
+
+struct GlucoseTargetsView: ChartContent {
+    let startMarker: Date
+    let endMarker: Date
+    let units: GlucoseUnits
+    let bgTargets: BGTargets
+
+    var body: some ChartContent {
+        drawGlucoseTargets()
+    }
+
+    private func drawGlucoseTargets() -> some ChartContent {
+        var targetProfiles: [TargetProfile] = []
+        let targets = bgTargets.targets
+
+        for (index, target) in targets.enumerated() {
+            let startTime = max(TimeInterval(target.offset * 60), startMarker.timeIntervalSinceReferenceDate)
+            let endTime: TimeInterval = {
+                if index + 1 < targets.count {
+                    return min(TimeInterval(targets[index + 1].offset * 60), endMarker.timeIntervalSinceReferenceDate)
+                } else {
+                    return endMarker.timeIntervalSinceReferenceDate
+                }
+            }()
+
+            if startTime < endTime { // Ensure valid range
+                targetProfiles.append(
+                    TargetProfile(
+                        value: units == .mgdL ? target.low : target.low.asMmolL,
+                        startTime: startTime,
+                        endTime: endTime
+                    )
+                )
+            }
+        }
+
+        // Draw Target Lines
+        return ForEach(targetProfiles, id: \.self) { profile in
+            // Horizontal Line for Target Range
+            LineMark(
+                x: .value("Time", Date(timeIntervalSince1970: profile.startTime)),
+                y: .value("Value", profile.value)
+            ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
+
+            LineMark(
+                x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
+                y: .value("Value", profile.value)
+            ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
+
+            // Vertical Transition Line to the Next Profile (if exists)
+            if let nextProfile = targetProfiles.first(where: { $0.startTime == profile.endTime }) {
+                LineMark(
+                    x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
+                    y: .value("Value", profile.value)
+                ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
+
+                LineMark(
+                    x: .value("Time", Date(timeIntervalSince1970: profile.endTime)),
+                    y: .value("Value", nextProfile.value)
+                ).lineStyle(.init(lineWidth: 1)).foregroundStyle(Color.green.gradient)
+            }
+        }
+    }
+}
+
+struct TargetProfile: Hashable {
+    let value: Decimal
+    let startTime: TimeInterval
+    let endTime: TimeInterval
+}
+
+private extension Date {
+    var startOfDay: Date {
+        Calendar.current.startOfDay(for: self)
+    }
+}

+ 8 - 0
FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift

@@ -137,6 +137,14 @@ extension MainChartView {
                     viewContext: context
                     viewContext: context
                 )
                 )
 
 
+                GlucoseTargetsView(
+                    startMarker: startMarker,
+                    endMarker: endMarker,
+                    units: state.units,
+
+                    bgTargets: state.bgTargets
+                )
+
                 GlucoseChartView(
                 GlucoseChartView(
                     glucoseData: state.glucoseFromPersistence,
                     glucoseData: state.glucoseFromPersistence,
                     units: state.units,
                     units: state.units,

+ 1 - 1
FreeAPS/Sources/Modules/Treatments/TreatmentsDataFlow.swift

@@ -6,6 +6,6 @@ protocol TreatmentsProvider: Provider {
     func getPumpSettings() async -> PumpSettings
     func getPumpSettings() async -> PumpSettings
     func getBasalProfile() async -> [BasalProfileEntry]
     func getBasalProfile() async -> [BasalProfileEntry]
     func getCarbRatios() async -> CarbRatios
     func getCarbRatios() async -> CarbRatios
-    func getBGTarget() async -> BGTargets
+    func getBGTargets() async -> BGTargets
     func getISFValues() async -> InsulinSensitivities
     func getISFValues() async -> InsulinSensitivities
 }
 }

+ 1 - 1
FreeAPS/Sources/Modules/Treatments/TreatmentsProvider.swift

@@ -18,7 +18,7 @@ extension Treatments {
                 ?? CarbRatios(units: .grams, schedule: [])
                 ?? CarbRatios(units: .grams, schedule: [])
         }
         }
 
 
-        func getBGTarget() async -> BGTargets {
+        func getBGTargets() async -> BGTargets {
             await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
             await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self)
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets))
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])
                 ?? BGTargets(units: .mgdL, userPreferredUnits: .mgdL, targets: [])

+ 1 - 1
FreeAPS/Sources/Modules/Treatments/TreatmentsStateModel.swift

@@ -303,7 +303,7 @@ extension Treatments {
                 let carbRatios = await provider.getCarbRatios()
                 let carbRatios = await provider.getCarbRatios()
                 entries = carbRatios.schedule.map { ($0.start, $0.ratio) }
                 entries = carbRatios.schedule.map { ($0.start, $0.ratio) }
             case .bgTarget:
             case .bgTarget:
-                let bgTargets = await provider.getBGTarget()
+                let bgTargets = await provider.getBGTargets()
                 entries = bgTargets.targets.map { ($0.start, $0.low) }
                 entries = bgTargets.targets.map { ($0.start, $0.low) }
             case .isf:
             case .isf:
                 let isfValues = await provider.getISFValues()
                 let isfValues = await provider.getISFValues()