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

Adjust BG bobble color to primary; make dynamic work for LA+dynamic island

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

+ 2 - 0
FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift

@@ -172,6 +172,8 @@ struct CurrentGlucoseView: View {
         // Ensure the thresholds are logical
         guard lowGlucose < highGlucose else { return .primary }
 
+        guard Decimal(lastGlucose) <= lowGlucose && Decimal(lastGlucose) >= highGlucose else { return .primary }
+
         return FreeAPS.getDynamicGlucoseColor(
             glucoseValue: Decimal(lastGlucose),
             highGlucoseColorValue: highGlucose,

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

@@ -7,7 +7,9 @@ struct LiveActivityAttributes: ActivityAttributes {
         let direction: String?
         let change: String
         let date: Date
-
+        let highGlucose: Decimal
+        let lowGlucose: Decimal
+        let glucoseColorScheme: String
         let detailedViewState: ContentAdditionalState?
 
         /// true for the first state that is set on the activity
@@ -18,9 +20,6 @@ struct LiveActivityAttributes: ActivityAttributes {
         let chart: [Decimal]
         let chartDate: [Date?]
         let rotationDegrees: Double
-        let highGlucose: Decimal
-        let lowGlucose: Decimal
-        let glucoseColorScheme: String
         let cob: Decimal
         let iob: Decimal
         let unit: String

+ 3 - 3
FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift

@@ -87,9 +87,6 @@ extension LiveActivityAttributes.ContentState {
                 chart: chartBG,
                 chartDate: chartDate,
                 rotationDegrees: rotationDegrees,
-                highGlucose: settings.high,
-                lowGlucose: settings.low,
-                glucoseColorScheme: settings.glucoseColorScheme.rawValue,
                 cob: Decimal(determination?.cob ?? 0),
                 iob: determination?.iob ?? 0 as Decimal,
                 unit: settings.units.rawValue,
@@ -105,6 +102,9 @@ extension LiveActivityAttributes.ContentState {
             direction: trendString,
             change: change,
             date: bg.date,
+            highGlucose: settings.high,
+            lowGlucose: settings.low,
+            glucoseColorScheme: settings.glucoseColorScheme.rawValue,
             detailedViewState: detailedState,
             isInitialState: false
         )

+ 3 - 0
FreeAPS/Sources/Services/LiveActivity/LiveActivityBridge.swift

@@ -192,6 +192,9 @@ import UIKit
                         direction: nil,
                         change: "--",
                         date: Date.now,
+                        highGlucose: settings.high,
+                        lowGlucose: settings.low,
+                        glucoseColorScheme: settings.glucoseColorScheme.rawValue,
                         detailedViewState: nil,
                         isInitialState: true
                     ),

+ 147 - 112
LiveActivity/LiveActivity.swift

@@ -22,77 +22,6 @@ enum GlucoseColorScheme: String, Equatable {
     case dynamicColor
 }
 
-// Helper function to decide how to pick the glucose color
-func getDynamicGlucoseColor(
-    glucoseValue: Decimal,
-    highGlucoseColorValue: Decimal,
-    lowGlucoseColorValue: Decimal,
-    targetGlucose: Decimal,
-    glucoseColorScheme: String,
-    offset: Decimal
-) -> Color {
-    let colorStyle = GlucoseColorScheme(rawValue: glucoseColorScheme) ?? .staticColor
-    // Convert Decimal to Int for high and low glucose values
-    let lowGlucose = lowGlucoseColorValue - offset
-    let highGlucose = highGlucoseColorValue + (offset * 1.75)
-    let targetGlucose = targetGlucose
-
-    // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences
-    if glucoseColorScheme == "dynamicColor" {
-        return calculateHueBasedGlucoseColor(
-            glucoseValue: glucoseValue,
-            highGlucose: highGlucose,
-            lowGlucose: lowGlucose,
-            targetGlucose: targetGlucose
-        )
-    }
-    // Otheriwse, use static (orange = high, red = low, green = range)
-    else {
-        if glucoseValue > highGlucose {
-            return Color.orange
-        } else if glucoseValue < lowGlucose {
-            return Color.red
-        } else {
-            return Color.green
-        }
-    }
-}
-
-// Dynamic color - Define the hue values for the key points
-// We'll shift color gradually one glucose point at a time
-// We'll shift through the rainbow colors of ROY-G-BIV from low to high
-// Start at red for lowGlucose, green for targetGlucose, and violet for highGlucose
-func calculateHueBasedGlucoseColor(
-    glucoseValue: Decimal,
-    highGlucose: Decimal,
-    lowGlucose: Decimal,
-    targetGlucose: Decimal
-) -> Color {
-    let redHue: CGFloat = 0.0 / 360.0 // 0 degrees
-    let greenHue: CGFloat = 120.0 / 360.0 // 120 degrees
-    let purpleHue: CGFloat = 270.0 / 360.0 // 270 degrees
-
-    // Calculate the hue based on the bgLevel
-    var hue: CGFloat
-    if glucoseValue <= lowGlucose {
-        hue = redHue
-    } else if glucoseValue >= highGlucose {
-        hue = purpleHue
-    } else if glucoseValue <= targetGlucose {
-        // Interpolate between red and green
-        let ratio = CGFloat(truncating: (glucoseValue - lowGlucose) / (targetGlucose - lowGlucose) as NSNumber)
-
-        hue = redHue + ratio * (greenHue - redHue)
-    } else {
-        // Interpolate between green and purple
-        let ratio = CGFloat(truncating: (glucoseValue - targetGlucose) / (highGlucose - targetGlucose) as NSNumber)
-        hue = greenHue + ratio * (purpleHue - greenHue)
-    }
-    // Return the color with full saturation and brightness
-    let color = Color(hue: hue, saturation: 0.6, brightness: 0.9)
-    return color
-}
-
 func rounded(_ value: Decimal, scale: Int, roundingMode: NSDecimalNumber.RoundingMode) -> Decimal {
     var result = Decimal()
     var toRound = value
@@ -136,6 +65,76 @@ extension NumberFormatter {
 }
 
 struct LiveActivity: Widget {
+    // Helper function to decide how to pick the glucose color
+    func getDynamicGlucoseColor(
+        glucoseValue: Decimal,
+        highGlucoseColorValue: Decimal,
+        lowGlucoseColorValue: Decimal,
+        targetGlucose: Decimal,
+        glucoseColorScheme: String,
+        offset: Decimal
+    ) -> Color {
+        // Convert Decimal to Int for high and low glucose values
+        let lowGlucose = lowGlucoseColorValue - offset
+        let highGlucose = highGlucoseColorValue + (offset * 1.75)
+        let targetGlucose = targetGlucose
+
+        // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences
+        if glucoseColorScheme == "dynamicColor" {
+            return calculateHueBasedGlucoseColor(
+                glucoseValue: glucoseValue,
+                highGlucose: highGlucose,
+                lowGlucose: lowGlucose,
+                targetGlucose: targetGlucose
+            )
+        }
+        // Otheriwse, use static (orange = high, red = low, green = range)
+        else {
+            if glucoseValue > highGlucose {
+                return Color.orange
+            } else if glucoseValue < lowGlucose {
+                return Color.red
+            } else {
+                return Color.green
+            }
+        }
+    }
+
+    // Dynamic color - Define the hue values for the key points
+    // We'll shift color gradually one glucose point at a time
+    // We'll shift through the rainbow colors of ROY-G-BIV from low to high
+    // Start at red for lowGlucose, green for targetGlucose, and violet for highGlucose
+    func calculateHueBasedGlucoseColor(
+        glucoseValue: Decimal,
+        highGlucose: Decimal,
+        lowGlucose: Decimal,
+        targetGlucose: Decimal
+    ) -> Color {
+        let redHue: CGFloat = 0.0 / 360.0 // 0 degrees
+        let greenHue: CGFloat = 120.0 / 360.0 // 120 degrees
+        let purpleHue: CGFloat = 270.0 / 360.0 // 270 degrees
+
+        // Calculate the hue based on the bgLevel
+        var hue: CGFloat
+        if glucoseValue <= lowGlucose {
+            hue = redHue
+        } else if glucoseValue >= highGlucose {
+            hue = purpleHue
+        } else if glucoseValue <= targetGlucose {
+            // Interpolate between red and green
+            let ratio = CGFloat(truncating: (glucoseValue - lowGlucose) / (targetGlucose - lowGlucose) as NSNumber)
+
+            hue = redHue + ratio * (greenHue - redHue)
+        } else {
+            // Interpolate between green and purple
+            let ratio = CGFloat(truncating: (glucoseValue - targetGlucose) / (highGlucose - targetGlucose) as NSNumber)
+            hue = greenHue + ratio * (purpleHue - greenHue)
+        }
+        // Return the color with full saturation and brightness
+        let color = Color(hue: hue, saturation: 0.6, brightness: 0.9)
+        return color
+    }
+
     private let dateFormatter: DateFormatter = {
         var f = DateFormatter()
         f.dateStyle = .none
@@ -258,7 +257,8 @@ struct LiveActivity: Widget {
     private func bgAndTrend(
         context: ActivityViewContext<LiveActivityAttributes>,
         size: Size,
-        dynamicColor _: Color
+        hasStaticColorScheme: Bool,
+        glucoseColor: Color
     ) -> (some View, Int) {
         var characters = 0
 
@@ -294,17 +294,15 @@ struct LiveActivity: Widget {
 
         let stack = HStack(spacing: spacing) {
             Text(bgText)
+                .foregroundColor(hasStaticColorScheme ? .primary : glucoseColor)
                 .strikethrough(context.isStale, pattern: .solid, color: .red.opacity(0.6))
+
             if let direction = directionText {
                 let text = Text(direction)
                 switch size {
                 case .minimal:
                     let scaledText = text.scaleEffect(x: 0.7, y: 0.7, anchor: .leading)
-                    if let warnColor {
-                        scaledText.foregroundStyle(warnColor)
-                    } else {
-                        scaledText
-                    }
+                    scaledText.foregroundStyle(hasStaticColorScheme ? .primary : glucoseColor)
                 case .compact:
                     text.scaleEffect(x: 0.8, y: 0.8, anchor: .leading).padding(.trailing, -3)
 
@@ -313,7 +311,7 @@ struct LiveActivity: Widget {
                 }
             }
         }
-        .foregroundStyle(context.isStale ? Color.primary.opacity(0.5) : Color.primary)
+        .foregroundColor(context.isStale ? Color.primary.opacity(0.5) : (hasStaticColorScheme ? .primary : glucoseColor))
 
         return (stack, characters)
     }
@@ -339,7 +337,8 @@ struct LiveActivity: Widget {
 
     @ViewBuilder func chart(
         context: ActivityViewContext<LiveActivityAttributes>,
-        additionalState: LiveActivityAttributes.ContentAdditionalState
+        additionalState: LiveActivityAttributes.ContentAdditionalState,
+        glucoseColor: Color
     ) -> some View {
         if context.isStale {
             Text("No data available")
@@ -348,9 +347,9 @@ struct LiveActivity: Widget {
             let min = min(additionalState.chart.min() ?? 45, 40) - 20
             let max = max(additionalState.chart.max() ?? 270, 300) + 50
 
-            let yAxisRuleMarkMin = additionalState.unit == "mg/dL" ? additionalState.lowGlucose : additionalState.lowGlucose
+            let yAxisRuleMarkMin = additionalState.unit == "mg/dL" ? context.state.lowGlucose : context.state.lowGlucose
                 .asMmolL
-            let yAxisRuleMarkMax = additionalState.unit == "mg/dL" ? additionalState.highGlucose : additionalState.highGlucose
+            let yAxisRuleMarkMax = additionalState.unit == "mg/dL" ? context.state.highGlucose : context.state.highGlucose
                 .asMmolL
 
             Chart {
@@ -368,16 +367,7 @@ struct LiveActivity: Widget {
                         y: .value("Value", displayValue)
                     ).symbolSize(15)
 
-                    let color = getDynamicGlucoseColor(
-                        glucoseValue: currentValue,
-                        highGlucoseColorValue: additionalState.highGlucose,
-                        lowGlucoseColorValue: additionalState.lowGlucose,
-                        targetGlucose: 90,
-                        glucoseColorScheme: additionalState.glucoseColorScheme ?? "staticColor",
-                        offset: additionalState.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL
-                    )
-
-                    pointMark.foregroundStyle(color)
+                    pointMark.foregroundStyle(glucoseColor)
                 }
             }
             .chartYAxis {
@@ -396,9 +386,20 @@ struct LiveActivity: Widget {
     }
 
     @ViewBuilder func content(context: ActivityViewContext<LiveActivityAttributes>) -> some View {
+        let hasStaticColorScheme = context.state.glucoseColorScheme == "staticColor"
+        let glucoseColor = getDynamicGlucoseColor(
+            glucoseValue: Decimal(string: context.state.bg) ?? 100,
+            highGlucoseColorValue: context.state.highGlucose,
+            lowGlucoseColorValue: context.state.lowGlucose,
+            targetGlucose: 90,
+            glucoseColorScheme: context.state.glucoseColorScheme,
+            offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL
+        )
+
         if let detailedViewState = context.state.detailedViewState {
             HStack(spacing: 12) {
-                chart(context: context, additionalState: detailedViewState).frame(maxWidth: UIScreen.main.bounds.width / 1.8)
+                chart(context: context, additionalState: detailedViewState, glucoseColor: glucoseColor)
+                    .frame(maxWidth: UIScreen.main.bounds.width / 1.8)
                 VStack(alignment: .leading) {
                     Spacer()
                     bgLabel(context: context, additionalState: detailedViewState)
@@ -417,15 +418,6 @@ struct LiveActivity: Widget {
             .activityBackgroundTint(Color.black.opacity(0.8))
         } else {
             Group {
-                let glucoseColor = getDynamicGlucoseColor(
-                    glucoseValue: Decimal(string: context.state.bg) ?? 100,
-                    highGlucoseColorValue: context.state.detailedViewState?.highGlucose ?? 180,
-                    lowGlucoseColorValue: context.state.detailedViewState?.lowGlucose ?? 70,
-                    targetGlucose: 90,
-                    glucoseColorScheme: context.state.detailedViewState?.glucoseColorScheme ?? "staticColor",
-                    offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL
-                )
-
                 if context.state.isInitialState {
                     // add vertical and horizontal spacers around the label to ensure that the live activity view gets filled completely
                     HStack {
@@ -439,11 +431,21 @@ struct LiveActivity: Widget {
                     }
                 } else {
                     HStack(spacing: 3) {
-                        bgAndTrend(context: context, size: .expanded, dynamicColor: glucoseColor).0.font(.title)
+                        bgAndTrend(
+                            context: context,
+                            size: .expanded,
+                            hasStaticColorScheme: hasStaticColorScheme,
+                            glucoseColor: glucoseColor
+                        ).0.font(.title)
                         Spacer()
                         VStack(alignment: .trailing, spacing: 5) {
                             changeLabel(context: context).font(.title3)
-                            updatedLabel(context: context).font(.caption).foregroundStyle(.primary.opacity(0.7))
+                                .foregroundStyle(hasStaticColorScheme ? .primary : glucoseColor)
+                            updatedLabel(context: context).font(.caption)
+                                .foregroundStyle(
+                                    hasStaticColorScheme ? .primary
+                                        .opacity(0.7) : glucoseColor
+                                )
                         }
                     }
                 }
@@ -461,29 +463,38 @@ struct LiveActivity: Widget {
 
     func dynamicIsland(context: ActivityViewContext<LiveActivityAttributes>) -> DynamicIsland {
         let glucoseValueForColor = context.state.bg
-        let highGlucose = context.state.detailedViewState?.highGlucose ?? 180
-        let lowGlucose = context.state.detailedViewState?.lowGlucose ?? 70
+        let highGlucose = context.state.highGlucose
+        let lowGlucose = context.state.lowGlucose
+        let hasStaticColorScheme = context.state.glucoseColorScheme == "staticColor"
         let glucoseColor = getDynamicGlucoseColor(
             glucoseValue: Decimal(string: glucoseValueForColor) ?? 100,
             highGlucoseColorValue: highGlucose,
             lowGlucoseColorValue: lowGlucose,
             targetGlucose: 90,
-            glucoseColorScheme: context.state.detailedViewState?.glucoseColorScheme ?? "staticColor",
+            glucoseColorScheme: context.state.glucoseColorScheme,
             offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL
         )
 
+        print("Glucose color: \(glucoseColor)")
+
         return DynamicIsland {
             DynamicIslandExpandedRegion(.leading) {
-                bgAndTrend(context: context, size: .expanded, dynamicColor: glucoseColor).0.font(.title2).padding(.leading, 5)
+                bgAndTrend(
+                    context: context,
+                    size: .expanded,
+                    hasStaticColorScheme: hasStaticColorScheme,
+                    glucoseColor: glucoseColor
+                ).0.font(.title2).padding(.leading, 5)
             }
             DynamicIslandExpandedRegion(.trailing) {
                 changeLabel(context: context).font(.title2).padding(.trailing, 5)
+                    .foregroundStyle(hasStaticColorScheme ? .primary : glucoseColor)
             }
             DynamicIslandExpandedRegion(.bottom) {
                 if context.state.isInitialState {
                     expiredLabel()
                 } else if let detailedViewState = context.state.detailedViewState {
-                    chart(context: context, additionalState: detailedViewState)
+                    chart(context: context, additionalState: detailedViewState, glucoseColor: glucoseColor)
                 } else {
                     Group {
                         updatedLabel(context: context).font(.caption).foregroundStyle(Color.secondary)
@@ -500,11 +511,17 @@ struct LiveActivity: Widget {
                 }
             }
         } compactLeading: {
-            bgAndTrend(context: context, size: .compact, dynamicColor: glucoseColor).0.padding(.leading, 4)
+            bgAndTrend(context: context, size: .compact, hasStaticColorScheme: hasStaticColorScheme, glucoseColor: glucoseColor).0
+                .padding(.leading, 4)
         } compactTrailing: {
-            changeLabel(context: context).padding(.trailing, 4)
+            changeLabel(context: context).padding(.trailing, 4).foregroundStyle(hasStaticColorScheme ? .primary : glucoseColor)
         } minimal: {
-            let (_label, characterCount) = bgAndTrend(context: context, size: .minimal, dynamicColor: glucoseColor)
+            let (_label, characterCount) = bgAndTrend(
+                context: context,
+                size: .minimal,
+                hasStaticColorScheme: hasStaticColorScheme,
+                glucoseColor: glucoseColor
+            )
             let label = _label.padding(.leading, 7).padding(.trailing, 3)
 
             if characterCount < 4 {
@@ -516,7 +533,7 @@ struct LiveActivity: Widget {
             }
         }
         .widgetURL(URL(string: "Trio://"))
-        .keylineTint(Color.purple)
+        .keylineTint(hasStaticColorScheme ? Color.purple : glucoseColor)
         .contentMargins(.horizontal, 0, for: .minimal)
         .contentMargins(.trailing, 0, for: .compactLeading)
         .contentMargins(.leading, 0, for: .compactTrailing)
@@ -543,6 +560,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: "→",
             change: "+0.0",
             date: Date(),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: false
         )
@@ -554,6 +574,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: "↑↑",
             change: "+0.0",
             date: Date(),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: false
         )
@@ -565,6 +588,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: "↑↑↑",
             change: "+0.0",
             date: Date(),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: false
         )
@@ -577,6 +603,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: "↑",
             change: "+0",
             date: Date(),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: false
         )
@@ -588,6 +617,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: "↗︎",
             change: "+00",
             date: Date(),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: false
         )
@@ -599,6 +631,9 @@ private extension LiveActivityAttributes.ContentState {
             direction: nil,
             change: "--",
             date: Date().addingTimeInterval(-60 * 60),
+            highGlucose: 180,
+            lowGlucose: 70,
+            glucoseColorScheme: "staticColor",
             detailedViewState: nil,
             isInitialState: true
         )