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

Fix incorrect chart units and parsing for LiveActivity detailed

Deniz Cengiz 1 год назад
Родитель
Сommit
41a6a43a10

+ 3 - 3
FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift

@@ -15,11 +15,11 @@ struct LiveActivityAttributes: ActivityAttributes {
     }
 
     public struct ContentAdditionalState: Codable, Hashable {
-        let chart: [Double]
+        let chart: [Decimal]
         let chartDate: [Date?]
         let rotationDegrees: Double
-        let highGlucose: Double
-        let lowGlucose: Double
+        let highGlucose: Decimal
+        let lowGlucose: Decimal
         let cob: Decimal
         let iob: Decimal
         let unit: String

+ 8 - 20
FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift

@@ -79,32 +79,20 @@ extension LiveActivityAttributes.ContentState {
 
         switch settings.lockScreenView {
         case .detailed:
-            let chartBG = chart.map(\.glucose)
-
-            let conversionFactor: Double = settings.units == .mmolL ? 18.0 : 1.0
-            let convertedChartBG = chartBG.map { Double($0) / conversionFactor }
-
+            let chartBG = chart.map { Decimal($0.glucose) }
             let chartDate = chart.map(\.date)
 
             /// glucose limits from UI settings, not from notifications settings
-            let highGlucose = settings.high / Decimal(conversionFactor)
-            let lowGlucose = settings.low / Decimal(conversionFactor)
-
-            let cob = determination?.cob ?? 0
-            let iob = determination?.iob ?? 0
-            let unit = settings.units == .mmolL ? " mmol/L" : " mg/dL"
-            let isOverrideActive = override?.isActive ?? false
-
             detailedState = LiveActivityAttributes.ContentAdditionalState(
-                chart: convertedChartBG,
+                chart: chartBG,
                 chartDate: chartDate,
                 rotationDegrees: rotationDegrees,
-                highGlucose: Double(highGlucose),
-                lowGlucose: Double(lowGlucose),
-                cob: Decimal(cob),
-                iob: iob as Decimal,
-                unit: unit,
-                isOverrideActive: isOverrideActive
+                highGlucose: settings.high,
+                lowGlucose: settings.low,
+                cob: Decimal(determination?.cob ?? 0),
+                iob: determination?.iob ?? 0 as Decimal,
+                unit: settings.units.rawValue,
+                isOverrideActive: override?.isActive ?? false
             )
 
         case .simple:

+ 64 - 9
LiveActivity/LiveActivity.swift

@@ -1,5 +1,6 @@
 import ActivityKit
 import Charts
+import Foundation
 import SwiftUI
 import WidgetKit
 
@@ -9,6 +10,55 @@ private enum Size {
     case expanded
 }
 
+enum GlucoseUnits: String, Equatable {
+    case mgdL = "mg/dL"
+    case mmolL = "mmol/L"
+
+    static let exchangeRate: Decimal = 0.0555
+}
+
+func rounded(_ value: Decimal, scale: Int, roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
+    var result = Decimal()
+    var toRound = value
+    NSDecimalRound(&result, &toRound, scale, roundingMode)
+    return result
+}
+
+extension Int {
+    var asMmolL: Decimal {
+        rounded(Decimal(self) * GlucoseUnits.exchangeRate, scale: 1, roundingMode: .plain)
+    }
+
+    var formattedAsMmolL: String {
+        NumberFormatter.glucoseFormatter.string(from: asMmolL as NSDecimalNumber) ?? "\(asMmolL)"
+    }
+}
+
+extension Decimal {
+    var asMmolL: Decimal {
+        rounded(self * GlucoseUnits.exchangeRate, scale: 1, roundingMode: .plain)
+    }
+
+    var asMgdL: Decimal {
+        rounded(self / GlucoseUnits.exchangeRate, scale: 0, roundingMode: .plain)
+    }
+
+    var formattedAsMmolL: String {
+        NumberFormatter.glucoseFormatter.string(from: asMmolL as NSDecimalNumber) ?? "\(asMmolL)"
+    }
+}
+
+extension NumberFormatter {
+    static let glucoseFormatter: NumberFormatter = {
+        let formatter = NumberFormatter()
+        formatter.locale = Locale.current
+        formatter.numberStyle = .decimal
+        formatter.minimumFractionDigits = 1
+        formatter.maximumFractionDigits = 1
+        return formatter
+    }()
+}
+
 struct LiveActivity: Widget {
     private let dateFormatter: DateFormatter = {
         var f = DateFormatter()
@@ -215,27 +265,32 @@ struct LiveActivity: Widget {
             Text("No data available")
         } else {
             // Determine scale
-            let conversionFactor = additionalState.unit == "mmol/L" ? 0.0555 : 1
-            let min = (additionalState.chart.min() ?? 40 * conversionFactor) - 20 * conversionFactor
-            let max = (additionalState.chart.max() ?? 270 * conversionFactor) + 50 * conversionFactor
+            let min = (additionalState.chart.min() ?? 45) - 20
+            let max = (additionalState.chart.max() ?? 270) + 50
+
+            let yAxisRuleMarkMin = additionalState.unit == "mg/dL" ? additionalState.lowGlucose : additionalState.lowGlucose
+                .asMmolL
+            let yAxisRuleMarkMax = additionalState.unit == "mg/dL" ? additionalState.highGlucose : additionalState.highGlucose
+                .asMmolL
 
             Chart {
-                RuleMark(y: .value("High", additionalState.highGlucose))
+                RuleMark(y: .value("Low", yAxisRuleMarkMin))
                     .lineStyle(.init(lineWidth: 0.5, dash: [5]))
-                RuleMark(y: .value("Low", additionalState.lowGlucose))
+                RuleMark(y: .value("High", yAxisRuleMarkMax))
                     .lineStyle(.init(lineWidth: 0.5, dash: [5]))
 
                 ForEach(additionalState.chart.indices, id: \.self) { index in
                     let currentValue = additionalState.chart[index]
+                    let displayValue = additionalState.unit == "mg/dL" ? currentValue : currentValue.asMmolL
                     let chartDate = additionalState.chartDate[index] ?? Date()
                     let pointMark = PointMark(
                         x: .value("Time", chartDate),
-                        y: .value("Value", currentValue)
+                        y: .value("Value", displayValue)
                     ).symbolSize(15)
 
-                    if currentValue > additionalState.highGlucose {
+                    if displayValue > yAxisRuleMarkMax {
                         pointMark.foregroundStyle(Color.orange.gradient)
-                    } else if currentValue < additionalState.lowGlucose {
+                    } else if displayValue < yAxisRuleMarkMin {
                         pointMark.foregroundStyle(Color.red.gradient)
                     } else {
                         pointMark.foregroundStyle(Color.green.gradient)
@@ -248,7 +303,7 @@ struct LiveActivity: Widget {
                     AxisValueLabel().foregroundStyle(.secondary).font(.footnote)
                 }
             }
-            .chartYScale(domain: min ... max)
+            .chartYScale(domain: additionalState.unit == "mg/dL" ? min ... max : min.asMmolL ... max.asMmolL)
             .chartXAxis {
                 AxisMarks(position: .automatic) { _ in
                     AxisGridLine(stroke: .init(lineWidth: 0.2, dash: [2, 3])).foregroundStyle(Color.white)

+ 1 - 1
Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -1,5 +1,5 @@
 {
-  "originHash" : "f5c836c216c4ca7d356e3777e58d6d4f9502b03f3974891349eb775f4c4cf750",
+  "originHash" : "59ac7eba66375d6eb406e758cb0b9964f4b3b0ae45c5665596f00384c32262b9",
   "pins" : [
     {
       "identity" : "cryptoswift",