Просмотр исходного кода

setting for forecast lines/cone, add logic back for treatments view

polscm32 1 год назад
Родитель
Сommit
2afe7cd4fb

+ 1 - 0
FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json

@@ -43,6 +43,7 @@
   "yGridLines" : true,
   "oneDimensionalGraph" : false,
   "rulerMarks" : true,
+  "displayForecastsAsLines": false,
   "maxCarbs": 250,
   "maxFat": 250,
   "maxProtein": 250,

+ 5 - 0
FreeAPS/Sources/Models/FreeAPSSettings.swift

@@ -59,6 +59,7 @@ struct FreeAPSSettings: JSON, Equatable {
     var yGridLines: Bool = true
     var oneDimensionalGraph: Bool = false
     var rulerMarks: Bool = true
+    var displayForecastsAsLines: Bool = false
     var maxCarbs: Decimal = 250
     var maxFat: Decimal = 250
     var maxProtein: Decimal = 250
@@ -281,6 +282,10 @@ extension FreeAPSSettings: Decodable {
             settings.rulerMarks = rulerMarks
         }
 
+        if let displayForecastsAsLines = try? container.decode(Bool.self, forKey: .displayForecastsAsLines) {
+            settings.displayForecastsAsLines = displayForecastsAsLines
+        }
+
         if let overrideHbA1cUnit = try? container.decode(Bool.self, forKey: .overrideHbA1cUnit) {
             settings.overrideHbA1cUnit = overrideHbA1cUnit
         }

+ 3 - 0
FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift

@@ -108,6 +108,7 @@ extension Bolus {
         @Published var minForecast: [Int] = []
         @Published var maxForecast: [Int] = []
         @Published var minCount: Int = 12 // count of Forecasts drawn in 5 min distances, i.e. 12 means a min of 1 hour
+        @Published var displayForecastsAsLines: Bool = false
 
         let now = Date.now
 
@@ -151,6 +152,8 @@ extension Bolus {
             sweetMealFactor = settings.settings.sweetMealFactor
             displayPresets = settings.settings.displayPresets
 
+            displayForecastsAsLines = settings.settings.displayForecastsAsLines
+
             lowGlucose = units == .mgdL ? settingsManager.settings.low : settingsManager.settings.low.asMmolL
             highGlucose = units == .mgdL ? settingsManager.settings.high : settingsManager.settings.high.asMmolL
 

+ 50 - 3
FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift

@@ -11,7 +11,9 @@ struct ForeCastChart: View {
     @State private var startMarker = Date(timeIntervalSinceNow: -4 * 60 * 60)
 
     private var endMarker: Date {
-        Date(timeIntervalSinceNow: TimeInterval(2 * 5 * state.minCount * 60)) // min is 2h -> (2*1h = 2*(5*12*60))
+        state
+            .displayForecastsAsLines ? Date(timeIntervalSinceNow: TimeInterval(hours: 3)) :
+            Date(timeIntervalSinceNow: TimeInterval(2 * 5 * state.minCount * 60)) // min is 2h -> (2*1h = 2*(5*12*60))
     }
 
     var body: some View {
@@ -48,12 +50,18 @@ struct ForeCastChart: View {
         Chart {
             drawGlucose()
             drawCurrentTimeMarker()
-            drawForecastArea()
+
+            if state.displayForecastsAsLines {
+                drawForecastLines()
+            } else {
+                drawForecastCone()
+            }
         }
         .chartXAxis { forecastChartXAxis }
         .chartXScale(domain: startMarker ... endMarker)
         .chartYAxis { forecastChartYAxis }
         .chartYScale(domain: units == .mgdL ? 0 ... 300 : 0.asMmolL ... 300.asMmolL)
+        .backport.chartForegroundStyleScale(state: state)
     }
 
     private func drawGlucose() -> some ChartContent {
@@ -89,7 +97,7 @@ struct ForeCastChart: View {
         return currentTime.addingTimeInterval(timeInterval)
     }
 
-    private func drawForecastArea() -> some ChartContent {
+    private func drawForecastCone() -> some ChartContent {
         ForEach(0 ..< max(state.minForecast.count, state.maxForecast.count), id: \.self) { index in
             if index < state.minForecast.count, index < state.maxForecast.count {
                 let yMinValue = Decimal(state.minForecast[index]) <= 300 ? Decimal(state.minForecast[index]) : Decimal(300)
@@ -106,6 +114,30 @@ struct ForeCastChart: View {
         }
     }
 
+    private func drawForecastLines() -> some ChartContent {
+        let predictions = state.predictionsForChart
+
+        // Prepare the prediction data with only the first 36 values, i.e. 3 hours in the future
+        let predictionData = [
+            ("IOB", predictions?.iob?.prefix(36)),
+            ("ZT", predictions?.zt?.prefix(36)),
+            ("COB", predictions?.cob?.prefix(36)),
+            ("UAM", predictions?.uam?.prefix(36))
+        ]
+
+        return ForEach(predictionData, id: \.0) { name, values in
+            if let values = values {
+                ForEach(values.indices, id: \.self) { index in
+                    LineMark(
+                        x: .value("Time", timeForIndex(Int32(index))),
+                        y: .value("Value", units == .mgdL ? Decimal(values[index]) : Decimal(values[index]).asMmolL)
+                    )
+                    .foregroundStyle(by: .value("Prediction Type", name))
+                }
+            }
+        }
+    }
+
     private func drawCurrentTimeMarker() -> some ChartContent {
         RuleMark(
             x: .value(
@@ -133,3 +165,18 @@ struct ForeCastChart: View {
         }
     }
 }
+
+extension Backport {
+    @ViewBuilder func chartForegroundStyleScale(state: Bolus.StateModel) -> some View {
+        if state.displayForecastsAsLines {
+            content.chartForegroundStyleScale([
+                "IOB": .blue,
+                "UAM": Color.uam,
+                "ZT": Color.zt,
+                "COB": .orange
+            ])
+        } else {
+            content
+        }
+    }
+}

+ 2 - 0
FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift

@@ -16,6 +16,7 @@ extension StatConfig {
         @Published var yGridLines: Bool = false
         @Published var oneDimensionalGraph = false
         @Published var rulerMarks: Bool = true
+        @Published var displayForecastsAsLines: Bool = false
 
         var units: GlucoseUnits = .mgdL
 
@@ -27,6 +28,7 @@ extension StatConfig {
             subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 }
             subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 }
             subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 }
+            subscribeSetting(\.displayForecastsAsLines, on: $displayForecastsAsLines) { displayForecastsAsLines = $0 }
             subscribeSetting(\.useFPUconversion, on: $useFPUconversion) { useFPUconversion = $0 }
             subscribeSetting(\.tins, on: $tins) { tins = $0 }
             subscribeSetting(\.skipBolusScreenAfterCarbs, on: $skipBolusScreenAfterCarbs) { skipBolusScreenAfterCarbs = $0 }

+ 1 - 0
FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift

@@ -56,6 +56,7 @@ extension StatConfig {
                         TextFieldWithToolBar(text: $state.hours, placeholder: "6", numberFormatter: carbsFormatter)
                         Text("hours").foregroundColor(.secondary)
                     }
+                    Toggle("Show Forecasts as Lines", isOn: $state.displayForecastsAsLines)
                 } header: { Text("Home Chart settings ") }
 
                 Section {