瀏覽代碼

More settings for Charts and for Statistics and for Glucose. Change the defaults.

Jon Mårtensson 3 年之前
父節點
當前提交
3ca0600214

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

@@ -27,5 +27,9 @@
     "timeCap": 8,
     "minuteInterval": 30,
     "delay": 60,
-    "displayOnWatch": "BGTarget"
+    "displayOnWatch": "BGTarget",
+    "hours": 6,
+    "xGridLines": false,
+    "yGridLines": true,
+    "oneDimensionalGraph": false
 }

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

@@ -35,6 +35,10 @@ struct FreeAPSSettings: JSON, Equatable {
     var high: Decimal = 145
     var low: Decimal = 70
     var uploadStats: Bool = false
+    var hours: Int = 6
+    var xGridLines: Bool = false
+    var yGridLines: Bool = true
+    var oneDimensionalGraph: Bool = false
 }
 
 extension FreeAPSSettings: Decodable {
@@ -180,6 +184,22 @@ extension FreeAPSSettings: Decodable {
             settings.uploadStats = uploadStats
         }
 
+        if let hours = try? container.decode(Int.self, forKey: .hours) {
+            settings.hours = hours
+        }
+
+        if let xGridLines = try? container.decode(Bool.self, forKey: .xGridLines) {
+            settings.xGridLines = xGridLines
+        }
+
+        if let yGridLines = try? container.decode(Bool.self, forKey: .yGridLines) {
+            settings.yGridLines = yGridLines
+        }
+
+        if let oneDimensionalGraph = try? container.decode(Bool.self, forKey: .oneDimensionalGraph) {
+            settings.oneDimensionalGraph = oneDimensionalGraph
+        }
+
         self = settings
     }
 }

+ 10 - 0
FreeAPS/Sources/Modules/Home/HomeStateModel.swift

@@ -54,6 +54,9 @@ extension Home {
         @Published var lowGlucose: Decimal = 4 / 0.0555
         @Published var highGlucose: Decimal = 10 / 0.0555
         @Published var overrideUnit = false
+        @Published var screenHours: Int = 6
+        @Published var displayXgridLines: Bool = false
+        @Published var displayYgridLines: Bool = false
 
         override func subscribe() {
             setupGlucose()
@@ -84,6 +87,9 @@ extension Home {
             lowGlucose = settingsManager.settings.low
             highGlucose = settingsManager.settings.high
             overrideUnit = settingsManager.settings.overrideHbA1cUnit
+            screenHours = settingsManager.settings.hours
+            displayXgridLines = settingsManager.settings.xGridLines
+            displayYgridLines = settingsManager.settings.yGridLines
 
             broadcaster.register(GlucoseObserver.self, observer: self)
             broadcaster.register(SuggestionObserver.self, observer: self)
@@ -389,6 +395,10 @@ extension Home.StateModel:
         lowGlucose = settingsManager.settings.low
         highGlucose = settingsManager.settings.high
         overrideUnit = settingsManager.settings.overrideHbA1cUnit
+        screenHours = settingsManager.settings.hours
+        displayXgridLines = settingsManager.settings.xGridLines
+        displayYgridLines = settingsManager.settings.yGridLines
+
         setupGlucose()
     }
 

+ 14 - 7
FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift

@@ -19,7 +19,6 @@ typealias GlucoseYRange = (minValue: Int, minY: CGFloat, maxValue: Int, maxY: CG
 struct MainChartView: View {
     private enum Config {
         static let endID = "End"
-        static let screenHours = 6
         static let basalHeight: CGFloat = 80
         static let topYPadding: CGFloat = 20
         static let bottomYPadding: CGFloat = 80
@@ -50,6 +49,9 @@ struct MainChartView: View {
     @Binding var smooth: Bool
     @Binding var highGlucose: Decimal
     @Binding var lowGlucose: Decimal
+    @Binding var screenHours: Int
+    @Binding var displayXgridLines: Bool
+    @Binding var displayYgridLines: Bool
 
     @State var didAppearTrigger = false
     @State private var glucoseDots: [CGRect] = []
@@ -167,7 +169,8 @@ struct MainChartView: View {
     }
 
     private func yGridView(fullSize: CGSize) -> some View {
-        ZStack {
+        let useColour = displayYgridLines ? Color.secondary : Color.clear
+        return ZStack {
             Path { path in
                 let range = glucoseYRange
                 let step = (range.maxY - range.minY) / CGFloat(Config.yLinesCount)
@@ -175,7 +178,8 @@ struct MainChartView: View {
                     path.move(to: CGPoint(x: 0, y: range.minY + CGFloat(line) * step))
                     path.addLine(to: CGPoint(x: fullSize.width, y: range.minY + CGFloat(line) * step))
                 }
-            }.stroke(Color.secondary, lineWidth: 0.15)
+            }.stroke(useColour, lineWidth: 0.15)
+
             // horizontal limits
             let range = glucoseYRange
             let topstep = (range.maxY - range.minY) / CGFloat(range.maxValue - range.minValue) *
@@ -263,7 +267,8 @@ struct MainChartView: View {
     @Environment(\.colorScheme) var colorScheme
 
     private func xGridView(fullSize: CGSize) -> some View {
-        ZStack {
+        let useColour = displayXgridLines ? Color.secondary : Color.clear
+        return ZStack {
             Path { path in
                 for hour in 0 ..< hours + hours {
                     let x = firstHourPosition(viewWidth: fullSize.width) +
@@ -273,7 +278,9 @@ struct MainChartView: View {
                     path.addLine(to: CGPoint(x: x, y: fullSize.height - 20))
                 }
             }
-            .stroke(Color.clear, lineWidth: 0.2)
+            .stroke(useColour, lineWidth: 0.15)
+
+            // .stroke(Color.secondary, lineWidth: 0.2)
 
             Path { path in // vertical timeline
                 let x = timeToXCoordinate(timerDate.timeIntervalSince1970, fullSize: fullSize)
@@ -854,7 +861,7 @@ extension MainChartView {
     }
 
     private func fullGlucoseWidth(viewWidth: CGFloat) -> CGFloat {
-        viewWidth * CGFloat(hours) / CGFloat(Config.screenHours)
+        viewWidth * CGFloat(hours) / CGFloat(max(screenHours, 6))
     }
 
     private func additionalWidth(viewWidth: CGFloat) -> CGFloat {
@@ -879,7 +886,7 @@ extension MainChartView {
     }
 
     private func oneSecondStep(viewWidth: CGFloat) -> CGFloat {
-        viewWidth / (CGFloat(Config.screenHours) * CGFloat(1.hours.timeInterval))
+        viewWidth / (CGFloat(max(screenHours, 6)) * CGFloat(1.hours.timeInterval))
     }
 
     private func maxPredValue() -> Int? {

+ 4 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -335,7 +335,10 @@ extension Home {
                     units: $state.units,
                     smooth: $state.smooth,
                     highGlucose: $state.highGlucose,
-                    lowGlucose: $state.lowGlucose
+                    lowGlucose: $state.lowGlucose,
+                    screenHours: $state.screenHours,
+                    displayXgridLines: $state.displayXgridLines,
+                    displayYgridLines: $state.displayYgridLines
                 )
             }
             .padding(.bottom)

+ 1 - 1
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -33,7 +33,7 @@ extension Settings {
                     Text("Fat And Protein Conversion").navigationLink(to: .fpuConfig, from: self)
                     Text("Profile Override").navigationLink(to: .overrideProfilesConfig, from: self)
                     Text("App Icons").navigationLink(to: .iconConfig, from: self)
-                    Text("Statistics and Glucose").navigationLink(to: .statisticsConfig, from: self)
+                    Text("Statistics and Home View").navigationLink(to: .statisticsConfig, from: self)
                 }
 
                 Section(header: Text("Configuration")) {

+ 2 - 0
FreeAPS/Sources/Modules/Stat/StatStateModel.swift

@@ -8,6 +8,7 @@ extension Stat {
         @Published var highLimit: Decimal?
         @Published var lowLimit: Decimal?
         @Published var overrideUnit: Bool?
+        @Published var layingChart: Bool?
 
         private(set) var units: GlucoseUnits = .mmolL
 
@@ -16,6 +17,7 @@ extension Stat {
             lowLimit = settingsManager.settings.low
             units = settingsManager.settings.units
             overrideUnit = settingsManager.settings.overrideHbA1cUnit
+            layingChart = settingsManager.settings.oneDimensionalGraph
         }
     }
 }

+ 40 - 4
FreeAPS/Sources/Modules/Stat/View/StatRootView.swift

@@ -9,7 +9,6 @@ extension Stat {
         let resolver: Resolver
         @StateObject var state = StateModel()
 
-        // @Environment(\.managedObjectContext) var moc
         @FetchRequest(
             entity: Readings.entity(),
             sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)], predicate: NSPredicate(
@@ -80,8 +79,14 @@ extension Stat {
         @State var conversionFactor = 0.0555
 
         @ViewBuilder func stats() -> some View {
-            bloodGlucose
-            Divider()
+            if state.layingChart ?? true {
+                bloodGlucose
+                Divider()
+            } else {
+                bloodGlucose
+                standingTIRchart
+                Divider()
+            }
             loops
             Divider()
             hba1c
@@ -100,7 +105,9 @@ extension Stat {
             case .Total:
                 glucoseChart90
             }
-            tirChart
+            if state.layingChart ?? true {
+                tirChart
+            }
         }
 
         var body: some View {
@@ -304,6 +311,35 @@ extension Stat {
             .chartForegroundStyleScale(["Low": .red, "In Range": .green, "High": .orange]).frame(maxHeight: 55)
         }
 
+        var standingTIRchart: some View {
+            let array = selectedDuration == .Today ? fetchedGlucoseDay : selectedDuration == .Day ?
+                fetchedGlucoseTwentyFourHours :
+                selectedDuration == .Week ? fetchedGlucoseWeek : selectedDuration == .Month ? fetchedGlucoseMonth :
+                selectedDuration == .Total ? fetchedGlucose : fetchedGlucoseDay
+            let fetched = tir(array)
+            let data: [ShapeModel] = [
+                .init(type: "Low", percent: fetched[0].decimal),
+                .init(type: "In Range", percent: fetched[1].decimal),
+                .init(type: "High", percent: fetched[2].decimal)
+            ]
+
+            return VStack(alignment: .center) {
+                Chart(data) { shape in
+                    BarMark(
+                        x: .value("Shape", shape.type),
+                        y: .value("Percentage", shape.percent)
+                    )
+                    .foregroundStyle(by: .value("Group", shape.type))
+                    .annotation(position: shape.percent < 5 ? .top : .overlay, alignment: .center) {
+                        Text(shape.percent == 0 ? "" : "\(shape.percent, format: .number.precision(.fractionLength(0))) %")
+                    }
+                }
+                .chartYAxis(.hidden)
+                .chartLegend(.hidden)
+                .chartForegroundStyleScale(["Low": .red, "In Range": .green, "High": .orange])
+            }
+        }
+
         var glucoseChart: some View {
             let count = fetchedGlucoseDay.count
             let lowLimit = (state.lowLimit ?? (4 * 0.0555)) * (state.units == .mmolL ? Decimal(conversionFactor) : 1)

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

@@ -6,6 +6,11 @@ extension StatConfig {
         @Published var low: Decimal = 4 / 0.0555
         @Published var high: Decimal = 10 / 0.0555
         @Published var uploadStats = false
+        @Published var hours: Decimal = 6
+        @Published var xGridLines = false
+        @Published var yGridLines: Bool = false
+        @Published var oneDimensionalGraph = false
+
         var units: GlucoseUnits = .mmolL
 
         override func subscribe() {
@@ -14,6 +19,9 @@ extension StatConfig {
 
             subscribeSetting(\.overrideHbA1cUnit, on: $overrideHbA1cUnit) { overrideHbA1cUnit = $0 }
             subscribeSetting(\.uploadStats, on: $uploadStats) { uploadStats = $0 }
+            subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 }
+            subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 }
+            subscribeSetting(\.oneDimensionalGraph, on: $oneDimensionalGraph) { oneDimensionalGraph = $0 }
 
             subscribeSetting(\.low, on: $low, initial: {
                 let value = max(min($0, 120), 40)
@@ -30,6 +38,13 @@ extension StatConfig {
                 guard units == .mmolL else { return $0 }
                 return $0.asMgdL
             })
+
+            subscribeSetting(\.hours, on: $hours.map(Int.init), initial: {
+                let value = max(min($0, 24), 6)
+                hours = Decimal(value)
+            }, map: {
+                $0
+            })
         }
     }
 }

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

@@ -26,9 +26,19 @@ extension StatConfig {
 
         var body: some View {
             Form {
-                Section(header: Text("Glucose")) {
+                Section(header: Text("Settings")) {
                     Toggle("Change HbA1c Unit", isOn: $state.overrideHbA1cUnit)
                     Toggle("Allow Upload of Statistics to NS", isOn: $state.uploadStats)
+                    Toggle("Display X - Grid lines", isOn: $state.xGridLines)
+                    Toggle("Display Y - Grid lines", isOn: $state.yGridLines)
+                    Toggle("Standing / Laying TIR Chart", isOn: $state.oneDimensionalGraph)
+
+                    HStack {
+                        Text("Hours (X-Axis)")
+                        Spacer()
+                        DecimalTextField("6", value: $state.hours, formatter: carbsFormatter)
+                        Text("hours").foregroundColor(.secondary)
+                    }
 
                     HStack {
                         Text("Low")