From ead22a6ed1c768a0c2c9c23c7d11ccb5e3c8880f Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Sat, 3 Aug 2024 17:01:26 -0400 Subject: [PATCH 01/17] Create IDEWorkspaceChecks.plist - No change with this commit, this is automatically created by XCode and is recommended to be committed - https://stackoverflow.com/questions/50367896/ideworkspacechecks-plist-file-suddenly-appear-after-updated-xcode --- FreeAPS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 FreeAPS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/FreeAPS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/FreeAPS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/FreeAPS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 205761d16b5e48b030809b78d628b7746b517d59 Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Sat, 3 Aug 2024 23:48:03 -0400 Subject: [PATCH 02/17] Create helper file for Dynamic BG Color functionality - Added BGColor as a utility file - BGColor contains functions for setting colors based on BG - TODO: read a settings toggle to determine whether to use dynamic or static color --- FreeAPS.xcodeproj/project.pbxproj | 6 ++++ FreeAPS/Sources/Helpers/BGColor.swift | 50 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 FreeAPS/Sources/Helpers/BGColor.swift diff --git a/FreeAPS.xcodeproj/project.pbxproj b/FreeAPS.xcodeproj/project.pbxproj index 09d0dc7c0..28ced897c 100644 --- a/FreeAPS.xcodeproj/project.pbxproj +++ b/FreeAPS.xcodeproj/project.pbxproj @@ -17,6 +17,8 @@ 110AEDEC2C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE72C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift */; }; 110AEDED2C51A0AE00615CC9 /* ShortcutsConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE82C51A0AE00615CC9 /* ShortcutsConfigProvider.swift */; }; 110AEDEE2C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE92C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift */; }; + 11E79B132C5F2585007893C2 /* BGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* BGColor.swift */; }; + 11E79B142C5F2585007893C2 /* BGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* BGColor.swift */; }; 17A9D0899046B45E87834820 /* CREditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8D5F457B5AFF763F8CF3DF /* CREditorProvider.swift */; }; 19012CDC291D2CB900FB8210 /* LoopStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19012CDB291D2CB900FB8210 /* LoopStats.swift */; }; 190EBCC429FF136900BA767D /* StatConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCC329FF136900BA767D /* StatConfigDataFlow.swift */; }; @@ -555,6 +557,7 @@ 110AEDE72C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigDataFlow.swift; sourceTree = ""; }; 110AEDE82C51A0AE00615CC9 /* ShortcutsConfigProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigProvider.swift; sourceTree = ""; }; 110AEDE92C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigStateModel.swift; sourceTree = ""; }; + 11E79B122C5F2585007893C2 /* BGColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGColor.swift; sourceTree = ""; }; 12204445D7632AF09264A979 /* PreferencesEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PreferencesEditorDataFlow.swift; sourceTree = ""; }; 19012CDB291D2CB900FB8210 /* LoopStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopStats.swift; sourceTree = ""; }; 190EBCC329FF136900BA767D /* StatConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatConfigDataFlow.swift; sourceTree = ""; }; @@ -1834,6 +1837,7 @@ BD1661302B82ADAB00256551 /* CustomProgressView.swift */, 581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */, DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */, + 11E79B122C5F2585007893C2 /* BGColor.swift */, ); path = Helpers; sourceTree = ""; @@ -3053,6 +3057,7 @@ 3811DEA925C9D88300A708ED /* AppearanceManager.swift in Sources */, CE7950242997D81700FA576E /* CGMSettingsView.swift in Sources */, 58237D9E2BCF0A6B00A47A79 /* PopupView.swift in Sources */, + 11E79B132C5F2585007893C2 /* BGColor.swift in Sources */, 38D0B3D925EC07C400CB6E88 /* CarbsEntry.swift in Sources */, 38A9260525F012D8009E3739 /* CarbRatios.swift in Sources */, 38FCF3D625E8FDF40078B0D1 /* MD5.swift in Sources */, @@ -3305,6 +3310,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 11E79B142C5F2585007893C2 /* BGColor.swift in Sources */, 6BCF84DE2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */, 6BCF84DE2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */, 6B1A8D1E2B14D91600E76752 /* LiveActivityBundle.swift in Sources */, diff --git a/FreeAPS/Sources/Helpers/BGColor.swift b/FreeAPS/Sources/Helpers/BGColor.swift new file mode 100644 index 000000000..8e55b6e00 --- /dev/null +++ b/FreeAPS/Sources/Helpers/BGColor.swift @@ -0,0 +1,50 @@ +import SwiftUI + +// Helper function to decide how to pick the BG color +public func setBGColor(bgValue: Int, lowGlucose: Int, highGlucose: Int, targetGlucose: Int) -> Color { + // TODO: + // Only use setDynamicBGColor if the setting is enabled in preferences + if true { + return setDynamicBGColor(bgValue: bgValue, lowGlucose: lowGlucose, highGlucose: highGlucose, targetGlucose: targetGlucose) + } + // Otheriwse, use static (orange = high, red = low, green = range) + else { + if bgValue > Int(highGlucose) { + return Color.orange + } else if bgValue < Int(lowGlucose) { + return Color.red + } else { + return Color.green + } + } +} + +// Dynamic color - Define the hue values for the key points +// We'll shift color gradually one BG 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 +public func setDynamicBGColor(bgValue: Int, lowGlucose: Int, highGlucose: Int, targetGlucose: Int) -> 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 bgValue <= lowGlucose { + hue = redHue + } else if bgValue >= highGlucose { + hue = purpleHue + } else if bgValue <= targetGlucose { + // Interpolate between red and green + let ratio = CGFloat(bgValue - lowGlucose) / CGFloat(targetGlucose - lowGlucose) + hue = redHue + ratio * (greenHue - redHue) + } else { + // Interpolate between green and purple + let ratio = CGFloat(bgValue - targetGlucose) / CGFloat(highGlucose - targetGlucose) + 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 +} From a209a728f2b5d8775ed0b8fb02ffc3a7fcf0cf77 Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Sat, 3 Aug 2024 23:48:49 -0400 Subject: [PATCH 03/17] Update the main chart view for dynamic BG color - Main chart view uses new BG color function to select dynamic BG color if opted in --- .../Home/View/Chart/MainChartView.swift | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index 1efc1f5c3..da7f3dbfc 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -207,6 +207,7 @@ extension MainChartView { Chart { /// high and low threshold lines if thresholdLines { + // Auggie - set the Color.loopYellow and Color.loopRed to use dynamic BG with low value passed in RuleMark(y: .value("High", highGlucose * conversionFactor)).foregroundStyle(Color.loopYellow) .lineStyle(.init(lineWidth: 1, dash: [5])) RuleMark(y: .value("Low", lowGlucose * conversionFactor)).foregroundStyle(Color.loopRed) @@ -306,6 +307,7 @@ extension MainChartView { } } + // Auggie TODO: dynamic BG color here in the pop-over text @ViewBuilder var selectionPopover: some View { if let sgv = selectedGlucose?.glucose { let glucoseToShow = Decimal(sgv) * conversionFactor @@ -463,44 +465,34 @@ extension MainChartView { } } + // Auggie TODO: use dynamic BG color function private func drawGlucose(dummy _: Bool) -> some ChartContent { - /// glucose point mark - /// filtering for high and low bounds in settings ForEach(state.glucoseFromPersistence) { item in + let glucoseLevel = Int(item.glucose) + let lowColorThreshold = Int(lowGlucose) + let highColorThreshold = Int(highGlucose) + let color = setBGColor( + bgValue: glucoseLevel, + lowGlucose: lowColorThreshold, + highGlucose: highColorThreshold, + targetGlucose: 90 // Auggie TODO: get the target color from preferences + ) + if smooth { - if item.glucose > Int(highGlucose) { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.orange.gradient).symbolSize(20).interpolationMethod(.cardinal) - } else if item.glucose < Int(lowGlucose) { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.red.gradient).symbolSize(20).interpolationMethod(.cardinal) - } else { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.green.gradient).symbolSize(20).interpolationMethod(.cardinal) - } + PointMark( + x: .value("Time", item.date ?? Date(), unit: .second), + y: .value("Value", Decimal(glucoseLevel) * conversionFactor) + ) + .foregroundStyle(color) + .symbolSize(20) + .interpolationMethod(.cardinal) } else { - if item.glucose > Int(highGlucose) { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.orange.gradient).symbolSize(20) - } else if item.glucose < Int(lowGlucose) { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.red.gradient).symbolSize(20) - } else { - PointMark( - x: .value("Time", item.date ?? Date(), unit: .second), - y: .value("Value", Decimal(item.glucose) * conversionFactor) - ).foregroundStyle(Color.green.gradient).symbolSize(20) - } + PointMark( + x: .value("Time", item.date ?? Date(), unit: .second), + y: .value("Value", Decimal(glucoseLevel) * conversionFactor) + ) + .foregroundStyle(color) + .symbolSize(20) } } } From b63c7c6832dfe84353926937fbf27ad9fa66dd29 Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Sat, 3 Aug 2024 23:49:12 -0400 Subject: [PATCH 04/17] Live Activity chart to use updated BG color function - LiveActivity chart view uses new BG color function to select dynamic BG color if opted in --- LiveActivity/LiveActivity.swift | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 310f79db6..5a3a696dc 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -233,13 +233,14 @@ struct LiveActivity: Widget { y: .value("Value", currentValue) ).symbolSize(15) - if currentValue > additionalState.highGlucose { - pointMark.foregroundStyle(Color.orange.gradient) - } else if currentValue < additionalState.lowGlucose { - pointMark.foregroundStyle(Color.red.gradient) - } else { - pointMark.foregroundStyle(Color.green.gradient) - } + let color = setBGColor( + bgValue: Int(currentValue), + lowGlucose: Int(additionalState.lowGlucose), + highGlucose: Int(additionalState.highGlucose), + targetGlucose: 90 // Auggie TODO: get the target color from preferences + ) + + pointMark.foregroundStyle(color) } } .chartYAxis { From a82dccd04e3d6d6f3d6084d5d4672329f23bf14f Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Tue, 6 Aug 2024 19:54:59 -0400 Subject: [PATCH 05/17] Dynamic BG color in graph views with this commit - Set up in graph views - Toggle is working from settings as wel --- .../defaults/freeaps/freeaps_settings.json | 1 + FreeAPS/Sources/Helpers/BGColor.swift | 21 +++++++++++++++---- FreeAPS/Sources/Models/FreeAPSSettings.swift | 5 +++++ .../Sources/Modules/Home/HomeStateModel.swift | 3 +++ .../Home/View/Chart/MainChartView.swift | 9 ++++---- .../Modules/Home/View/HomeRootView.swift | 1 + .../StatConfig/StatConfigStateModel.swift | 2 ++ .../StatConfig/View/StatConfigRootView.swift | 1 + 8 files changed, 34 insertions(+), 9 deletions(-) diff --git a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json index 0932fb461..f93dfd6a2 100644 --- a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json +++ b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json @@ -39,6 +39,7 @@ "high" : 180, "low" : 70, "hours" : 6, + "dynamicBGColor" : false, "xGridLines" : true, "yGridLines" : true, "oneDimensionalGraph" : false, diff --git a/FreeAPS/Sources/Helpers/BGColor.swift b/FreeAPS/Sources/Helpers/BGColor.swift index 8e55b6e00..2a94c72b7 100644 --- a/FreeAPS/Sources/Helpers/BGColor.swift +++ b/FreeAPS/Sources/Helpers/BGColor.swift @@ -1,11 +1,24 @@ +import CoreData +import Foundation import SwiftUI // Helper function to decide how to pick the BG color -public func setBGColor(bgValue: Int, lowGlucose: Int, highGlucose: Int, targetGlucose: Int) -> Color { +public func setBGColor(bgValue: Int, highBGColorValue: Decimal, lowBGColorValue: Decimal, dynamicBGColor: Bool) -> Color { + // Auggie - injected fails here + // Convert Decimal to Int for high and low glucose values + let lowGlucose = NSDecimalNumber(decimal: lowBGColorValue).intValue - 20 + let highGlucose = NSDecimalNumber(decimal: highBGColorValue).intValue + 20 + let targetGlucose = 90 + // TODO: // Only use setDynamicBGColor if the setting is enabled in preferences - if true { - return setDynamicBGColor(bgValue: bgValue, lowGlucose: lowGlucose, highGlucose: highGlucose, targetGlucose: targetGlucose) + if dynamicBGColor { + return setDynamicBGColor( + bgValue: bgValue, + highGlucose: Int(highGlucose), + lowGlucose: Int(lowGlucose), + targetGlucose: targetGlucose + ) } // Otheriwse, use static (orange = high, red = low, green = range) else { @@ -23,7 +36,7 @@ public func setBGColor(bgValue: Int, lowGlucose: Int, highGlucose: Int, targetGl // We'll shift color gradually one BG 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 -public func setDynamicBGColor(bgValue: Int, lowGlucose: Int, highGlucose: Int, targetGlucose: Int) -> Color { +public func setDynamicBGColor(bgValue: Int, highGlucose: Int, lowGlucose: Int, targetGlucose: Int) -> 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 diff --git a/FreeAPS/Sources/Models/FreeAPSSettings.swift b/FreeAPS/Sources/Models/FreeAPSSettings.swift index 30f848a63..277c333ba 100644 --- a/FreeAPS/Sources/Models/FreeAPSSettings.swift +++ b/FreeAPS/Sources/Models/FreeAPSSettings.swift @@ -55,6 +55,7 @@ struct FreeAPSSettings: JSON, Equatable { var high: Decimal = 180 var low: Decimal = 70 var hours: Int = 6 + var dynamicBGColor: Bool = false var xGridLines: Bool = true var yGridLines: Bool = true var oneDimensionalGraph: Bool = false @@ -265,6 +266,10 @@ extension FreeAPSSettings: Decodable { settings.hours = hours } + if let dynamicBGColor = try? container.decode(Bool.self, forKey: .dynamicBGColor) { + settings.dynamicBGColor = dynamicBGColor + } + if let xGridLines = try? container.decode(Bool.self, forKey: .xGridLines) { settings.xGridLines = xGridLines } diff --git a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift index 9685e4376..559ca8eca 100644 --- a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift +++ b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift @@ -49,6 +49,7 @@ extension Home { @Published var lowGlucose: Decimal = 4 / 0.0555 @Published var highGlucose: Decimal = 10 / 0.0555 @Published var overrideUnit: Bool = false + @Published var dynamicBGColor: Bool = false @Published var displayXgridLines: Bool = false @Published var displayYgridLines: Bool = false @Published var thresholdLines: Bool = false @@ -123,6 +124,7 @@ extension Home { lowGlucose = settingsManager.settings.low highGlucose = settingsManager.settings.high overrideUnit = settingsManager.settings.overrideHbA1cUnit + dynamicBGColor = settingsManager.settings.dynamicBGColor displayXgridLines = settingsManager.settings.xGridLines displayYgridLines = settingsManager.settings.yGridLines thresholdLines = settingsManager.settings.rulerMarks @@ -456,6 +458,7 @@ extension Home.StateModel: lowGlucose = settingsManager.settings.low highGlucose = settingsManager.settings.high overrideUnit = settingsManager.settings.overrideHbA1cUnit + dynamicBGColor = settingsManager.settings.dynamicBGColor displayXgridLines = settingsManager.settings.xGridLines displayYgridLines = settingsManager.settings.yGridLines thresholdLines = settingsManager.settings.rulerMarks diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index da7f3dbfc..ead76b3ad 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -47,6 +47,7 @@ struct MainChartView: View { @Binding var highGlucose: Decimal @Binding var lowGlucose: Decimal @Binding var screenHours: Int16 + @Binding var dynamicBGColor: Bool @Binding var displayXgridLines: Bool @Binding var displayYgridLines: Bool @Binding var thresholdLines: Bool @@ -469,13 +470,11 @@ extension MainChartView { private func drawGlucose(dummy _: Bool) -> some ChartContent { ForEach(state.glucoseFromPersistence) { item in let glucoseLevel = Int(item.glucose) - let lowColorThreshold = Int(lowGlucose) - let highColorThreshold = Int(highGlucose) let color = setBGColor( bgValue: glucoseLevel, - lowGlucose: lowColorThreshold, - highGlucose: highColorThreshold, - targetGlucose: 90 // Auggie TODO: get the target color from preferences + highBGColorValue: highGlucose, + lowBGColorValue: lowGlucose, + dynamicBGColor: dynamicBGColor ) if smooth { diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 2f8351fda..b32f99391 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -373,6 +373,7 @@ extension Home { highGlucose: $state.highGlucose, lowGlucose: $state.lowGlucose, screenHours: $state.hours, + dynamicBGColor: $state.dynamicBGColor, displayXgridLines: $state.displayXgridLines, displayYgridLines: $state.displayYgridLines, thresholdLines: $state.thresholdLines, diff --git a/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift b/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift index 39d04d282..8c1022c29 100644 --- a/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift +++ b/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift @@ -12,6 +12,7 @@ extension StatConfig { @Published var low: Decimal = 70 @Published var high: Decimal = 180 @Published var hours: Decimal = 6 + @Published var dynamicBGColor = false @Published var xGridLines = false @Published var yGridLines: Bool = false @Published var oneDimensionalGraph = false @@ -24,6 +25,7 @@ extension StatConfig { self.units = units subscribeSetting(\.overrideHbA1cUnit, on: $overrideHbA1cUnit) { overrideHbA1cUnit = $0 } + subscribeSetting(\.dynamicBGColor, on: $dynamicBGColor) { dynamicBGColor = $0 } subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 } subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 } subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 } diff --git a/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift b/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift index e7c1b47d5..64724287c 100644 --- a/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift +++ b/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift @@ -45,6 +45,7 @@ extension StatConfig { var body: some View { Form { Section { + Toggle("Use Dynamic BG Color", isOn: $state.dynamicBGColor) Toggle("Display Chart X - Grid lines", isOn: $state.xGridLines) Toggle("Display Chart Y - Grid lines", isOn: $state.yGridLines) Toggle("Display Chart Threshold lines for Low and High", isOn: $state.rulerMarks) From 52b9c0a4f1a775dd8ee4833ffcfead5d3ea778a5 Mon Sep 17 00:00:00 2001 From: Auggie Fisher Date: Tue, 6 Aug 2024 19:57:32 -0400 Subject: [PATCH 06/17] Dynamic BG Color into Live Activity with a flag - Dynamic BG color in live activity - Includes some extra redesign of live activity main view in dynamic island --- .../LiveActivity/LiveActitiyAttributes.swift | 1 + .../LiveActivityAttributes+Helper.swift | 1 + LiveActivity/LiveActivity.swift | 60 +++++++++++++++++-- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift index 466180a10..4127335bf 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift @@ -20,6 +20,7 @@ struct LiveActivityAttributes: ActivityAttributes { let rotationDegrees: Double let highGlucose: Double let lowGlucose: Double + let dynamicBGColor: Bool let cob: Decimal let iob: Decimal let unit: String diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift index 11064411e..3b9f7263d 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift @@ -101,6 +101,7 @@ extension LiveActivityAttributes.ContentState { rotationDegrees: rotationDegrees, highGlucose: Double(highGlucose), lowGlucose: Double(lowGlucose), + dynamicBGColor: settings.dynamicBGColor, cob: Decimal(cob), iob: iob as Decimal, unit: unit, diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 5a3a696dc..823aac45b 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -233,11 +233,13 @@ struct LiveActivity: Widget { y: .value("Value", currentValue) ).symbolSize(15) + // let color = setBGColor(bgValue: Int(currentValue), highBGColorValue: additionalState.highGlucose, lowBGColorValue: additionalState.lowGlucose, dynamicBGColor: additionalState.dynamicBGColor) + let color = setBGColor( bgValue: Int(currentValue), - lowGlucose: Int(additionalState.lowGlucose), - highGlucose: Int(additionalState.highGlucose), - targetGlucose: 90 // Auggie TODO: get the target color from preferences + highBGColorValue: Decimal(additionalState.highGlucose), + lowBGColorValue: Decimal(additionalState.lowGlucose), + dynamicBGColor: additionalState.dynamicBGColor ) pointMark.foregroundStyle(color) @@ -314,7 +316,12 @@ struct LiveActivity: Widget { } func dynamicIsland(context: ActivityViewContext) -> DynamicIsland { - DynamicIsland { + let bgValueForColor = Int(context.state.bg) ?? 100 + let highGlucose = context.state.detailedViewState?.highGlucose ?? 180 + let lowGlucose = context.state.detailedViewState?.lowGlucose ?? 70 + let dynamicBGColor = context.state.detailedViewState?.dynamicBGColor ?? false + + return DynamicIsland { DynamicIslandExpandedRegion(.leading) { bgAndTrend(context: context, size: .expanded).0.font(.title2).padding(.leading, 5) } @@ -342,9 +349,50 @@ struct LiveActivity: Widget { } } } compactLeading: { - bgAndTrend(context: context, size: .compact).0.padding(.leading, 4) + // bgAndTrend(context: context, size: .compact).0.padding(.leading, 4) + HStack(spacing: 1) { + Image(systemName: "drop.fill") + .renderingMode(.template) + .foregroundStyle(setBGColor( + bgValue: bgValueForColor, + highBGColorValue: Decimal(highGlucose), + lowBGColorValue: Decimal(lowGlucose), + dynamicBGColor: dynamicBGColor + )) + .baselineOffset(-2) + Text("\(context.state.bg)") + .foregroundStyle(setBGColor( + bgValue: bgValueForColor, + highBGColorValue: Decimal(highGlucose), + lowBGColorValue: Decimal(lowGlucose), + dynamicBGColor: dynamicBGColor + )) + .minimumScaleFactor(0.1) + .fontWeight(.bold) + } } compactTrailing: { - changeLabel(context: context).padding(.trailing, 4) + // changeLabel(context: context).padding(.trailing, 4) + HStack(spacing: -5) { + Text("\(context.state.direction ?? "--")") + .foregroundStyle(setBGColor( + bgValue: bgValueForColor, + highBGColorValue: Decimal(highGlucose), + lowBGColorValue: Decimal(lowGlucose), + dynamicBGColor: dynamicBGColor + )) + .minimumScaleFactor(0.1) + .fontWeight(.bold) + .baselineOffset(-2) + Text("\(context.state.change)") + .foregroundStyle(setBGColor( + bgValue: bgValueForColor, + highBGColorValue: Decimal(highGlucose), + lowBGColorValue: Decimal(lowGlucose), + dynamicBGColor: dynamicBGColor + )) + .minimumScaleFactor(0.1) + .fontWeight(.bold) + } } minimal: { let (_label, characterCount) = bgAndTrend(context: context, size: .minimal) let label = _label.padding(.leading, 7).padding(.trailing, 3) From 573e235d17a062e9d7ff8ac6da4e46de401761e9 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Wed, 28 Aug 2024 21:37:16 +0200 Subject: [PATCH 07/17] Refactoring + set target in main chart via setting --- FreeAPS.xcodeproj/project.pbxproj | 12 +-- .../defaults/freeaps/freeaps_settings.json | 2 +- FreeAPS/Sources/Helpers/BGColor.swift | 63 ------------- .../Sources/Helpers/DynamicGlucoseColor.swift | 73 +++++++++++++++ FreeAPS/Sources/Models/FreeAPSSettings.swift | 6 +- .../Sources/Modules/Home/HomeProvider.swift | 6 ++ .../Sources/Modules/Home/HomeStateModel.swift | 61 +++++++++++- .../Home/View/Chart/MainChartView.swift | 59 ++++++------ .../Modules/Home/View/HomeRootView.swift | 3 +- .../StatConfig/StatConfigStateModel.swift | 4 +- .../StatConfig/View/StatConfigRootView.swift | 2 +- .../LiveActivity/LiveActitiyAttributes.swift | 2 +- .../LiveActivityAttributes+Helper.swift | 2 +- LiveActivity/LiveActivity.swift | 92 ++++++++----------- .../xcshareddata/swiftpm/Package.resolved | 4 +- 15 files changed, 226 insertions(+), 165 deletions(-) delete mode 100644 FreeAPS/Sources/Helpers/BGColor.swift create mode 100644 FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift diff --git a/FreeAPS.xcodeproj/project.pbxproj b/FreeAPS.xcodeproj/project.pbxproj index 0835da81a..dd4a84689 100644 --- a/FreeAPS.xcodeproj/project.pbxproj +++ b/FreeAPS.xcodeproj/project.pbxproj @@ -17,8 +17,8 @@ 110AEDEC2C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE72C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift */; }; 110AEDED2C51A0AE00615CC9 /* ShortcutsConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE82C51A0AE00615CC9 /* ShortcutsConfigProvider.swift */; }; 110AEDEE2C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AEDE92C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift */; }; - 11E79B132C5F2585007893C2 /* BGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* BGColor.swift */; }; - 11E79B142C5F2585007893C2 /* BGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* BGColor.swift */; }; + 11E79B132C5F2585007893C2 /* DynamicGlucoseColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* DynamicGlucoseColor.swift */; }; + 11E79B142C5F2585007893C2 /* DynamicGlucoseColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11E79B122C5F2585007893C2 /* DynamicGlucoseColor.swift */; }; 17A9D0899046B45E87834820 /* CREditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8D5F457B5AFF763F8CF3DF /* CREditorProvider.swift */; }; 19012CDC291D2CB900FB8210 /* LoopStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19012CDB291D2CB900FB8210 /* LoopStats.swift */; }; 190EBCC429FF136900BA767D /* StatConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 190EBCC329FF136900BA767D /* StatConfigDataFlow.swift */; }; @@ -562,7 +562,7 @@ 110AEDE72C51A0AE00615CC9 /* ShortcutsConfigDataFlow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigDataFlow.swift; sourceTree = ""; }; 110AEDE82C51A0AE00615CC9 /* ShortcutsConfigProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigProvider.swift; sourceTree = ""; }; 110AEDE92C51A0AE00615CC9 /* ShortcutsConfigStateModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShortcutsConfigStateModel.swift; sourceTree = ""; }; - 11E79B122C5F2585007893C2 /* BGColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGColor.swift; sourceTree = ""; }; + 11E79B122C5F2585007893C2 /* DynamicGlucoseColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicGlucoseColor.swift; sourceTree = ""; }; 12204445D7632AF09264A979 /* PreferencesEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PreferencesEditorDataFlow.swift; sourceTree = ""; }; 19012CDB291D2CB900FB8210 /* LoopStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopStats.swift; sourceTree = ""; }; 190EBCC329FF136900BA767D /* StatConfigDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatConfigDataFlow.swift; sourceTree = ""; }; @@ -1847,7 +1847,7 @@ BD1661302B82ADAB00256551 /* CustomProgressView.swift */, 581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */, DD1DB7CB2BECCA1F0048B367 /* BuildDetails.swift */, - 11E79B122C5F2585007893C2 /* BGColor.swift */, + 11E79B122C5F2585007893C2 /* DynamicGlucoseColor.swift */, C20BC6CD2C66FBFD002BC1C6 /* Rounding.swift */, ); path = Helpers; @@ -3074,7 +3074,7 @@ 3811DEA925C9D88300A708ED /* AppearanceManager.swift in Sources */, CE7950242997D81700FA576E /* CGMSettingsView.swift in Sources */, 58237D9E2BCF0A6B00A47A79 /* PopupView.swift in Sources */, - 11E79B132C5F2585007893C2 /* BGColor.swift in Sources */, + 11E79B132C5F2585007893C2 /* DynamicGlucoseColor.swift in Sources */, 38D0B3D925EC07C400CB6E88 /* CarbsEntry.swift in Sources */, 38A9260525F012D8009E3739 /* CarbRatios.swift in Sources */, 38FCF3D625E8FDF40078B0D1 /* MD5.swift in Sources */, @@ -3330,7 +3330,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 11E79B142C5F2585007893C2 /* BGColor.swift in Sources */, + 11E79B142C5F2585007893C2 /* DynamicGlucoseColor.swift in Sources */, 6BCF84DE2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */, 6BCF84DE2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */, 6B1A8D1E2B14D91600E76752 /* LiveActivityBundle.swift in Sources */, diff --git a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json index e3637d03a..bb42e28b1 100644 --- a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json +++ b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json @@ -39,7 +39,7 @@ "high" : 180, "low" : 70, "hours" : 6, - "dynamicBGColor" : false, + "dynamicGlucoseColor" : false, "xGridLines" : true, "yGridLines" : true, "oneDimensionalGraph" : false, diff --git a/FreeAPS/Sources/Helpers/BGColor.swift b/FreeAPS/Sources/Helpers/BGColor.swift deleted file mode 100644 index 2a94c72b7..000000000 --- a/FreeAPS/Sources/Helpers/BGColor.swift +++ /dev/null @@ -1,63 +0,0 @@ -import CoreData -import Foundation -import SwiftUI - -// Helper function to decide how to pick the BG color -public func setBGColor(bgValue: Int, highBGColorValue: Decimal, lowBGColorValue: Decimal, dynamicBGColor: Bool) -> Color { - // Auggie - injected fails here - // Convert Decimal to Int for high and low glucose values - let lowGlucose = NSDecimalNumber(decimal: lowBGColorValue).intValue - 20 - let highGlucose = NSDecimalNumber(decimal: highBGColorValue).intValue + 20 - let targetGlucose = 90 - - // TODO: - // Only use setDynamicBGColor if the setting is enabled in preferences - if dynamicBGColor { - return setDynamicBGColor( - bgValue: bgValue, - highGlucose: Int(highGlucose), - lowGlucose: Int(lowGlucose), - targetGlucose: targetGlucose - ) - } - // Otheriwse, use static (orange = high, red = low, green = range) - else { - if bgValue > Int(highGlucose) { - return Color.orange - } else if bgValue < Int(lowGlucose) { - return Color.red - } else { - return Color.green - } - } -} - -// Dynamic color - Define the hue values for the key points -// We'll shift color gradually one BG 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 -public func setDynamicBGColor(bgValue: Int, highGlucose: Int, lowGlucose: Int, targetGlucose: Int) -> 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 bgValue <= lowGlucose { - hue = redHue - } else if bgValue >= highGlucose { - hue = purpleHue - } else if bgValue <= targetGlucose { - // Interpolate between red and green - let ratio = CGFloat(bgValue - lowGlucose) / CGFloat(targetGlucose - lowGlucose) - hue = redHue + ratio * (greenHue - redHue) - } else { - // Interpolate between green and purple - let ratio = CGFloat(bgValue - targetGlucose) / CGFloat(highGlucose - targetGlucose) - 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 -} diff --git a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift new file mode 100644 index 000000000..444724735 --- /dev/null +++ b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift @@ -0,0 +1,73 @@ +import CoreData +import Foundation +import SwiftUI + +// Helper function to decide how to pick the glucose color +public func getDynamicGlucoseColor( + glucoseValue: Decimal, + highGlucoseColorValue: Decimal, + lowGlucoseColorValue: Decimal, + targetGlucose: Decimal, + dynamicGlucoseColor: Bool, + offset: Decimal +) -> Color { + // Convert Decimal to Int for high and low glucose values + let lowGlucose = lowGlucoseColorValue - offset + let highGlucose = highGlucoseColorValue + offset + let targetGlucose = targetGlucose + + // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences + if dynamicGlucoseColor { + 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 +public 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 +} diff --git a/FreeAPS/Sources/Models/FreeAPSSettings.swift b/FreeAPS/Sources/Models/FreeAPSSettings.swift index 57b9be75c..6448238bd 100644 --- a/FreeAPS/Sources/Models/FreeAPSSettings.swift +++ b/FreeAPS/Sources/Models/FreeAPSSettings.swift @@ -55,7 +55,7 @@ struct FreeAPSSettings: JSON, Equatable { var high: Decimal = 180 var low: Decimal = 70 var hours: Int = 6 - var dynamicBGColor: Bool = false + var dynamicGlucoseColor: Bool = false var xGridLines: Bool = true var yGridLines: Bool = true var oneDimensionalGraph: Bool = false @@ -267,8 +267,8 @@ extension FreeAPSSettings: Decodable { settings.hours = hours } - if let dynamicBGColor = try? container.decode(Bool.self, forKey: .dynamicBGColor) { - settings.dynamicBGColor = dynamicBGColor + if let dynamicGlucoseColor = try? container.decode(Bool.self, forKey: .dynamicGlucoseColor) { + settings.dynamicGlucoseColor = dynamicGlucoseColor } if let xGridLines = try? container.decode(Bool.self, forKey: .xGridLines) { diff --git a/FreeAPS/Sources/Modules/Home/HomeProvider.swift b/FreeAPS/Sources/Modules/Home/HomeProvider.swift index 10f76c632..709791f3f 100644 --- a/FreeAPS/Sources/Modules/Home/HomeProvider.swift +++ b/FreeAPS/Sources/Modules/Home/HomeProvider.swift @@ -53,5 +53,11 @@ extension Home { storage.retrieve(OpenAPS.Settings.pumpProfile, as: Autotune.self)?.basalProfile ?? [BasalProfileEntry(start: "00:00", minutes: 0, rate: 1)] } + + func getBGTarget() async -> BGTargets { + await storage.retrieveAsync(OpenAPS.Settings.bgTargets, as: BGTargets.self) + ?? BGTargets(from: OpenAPS.defaults(for: OpenAPS.Settings.bgTargets)) + ?? BGTargets(units: .mgdL, userPrefferedUnits: .mgdL, targets: []) + } } } diff --git a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift index 0e65bc000..2662bb9d3 100644 --- a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift +++ b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift @@ -49,8 +49,9 @@ extension Home { @Published var maxValue: Decimal = 1.2 @Published var lowGlucose: Decimal = 70 @Published var highGlucose: Decimal = 180 + @Published var currentGlucoseTarget: Decimal = 100 @Published var overrideUnit: Bool = false - @Published var dynamicBGColor: Bool = false + @Published var dynamicGlucoseColor: Bool = false @Published var displayXgridLines: Bool = false @Published var displayYgridLines: Bool = false @Published var thresholdLines: Bool = false @@ -129,8 +130,11 @@ extension Home { maxValue = settingsManager.preferences.autosensMax lowGlucose = units == .mgdL ? settingsManager.settings.low : settingsManager.settings.low.asMmolL highGlucose = units == .mgdL ? settingsManager.settings.high : settingsManager.settings.high.asMmolL + Task { + await self.getCurrentGlucoseTarget() + } overrideUnit = settingsManager.settings.overrideHbA1cUnit - dynamicBGColor = settingsManager.settings.dynamicBGColor + dynamicGlucoseColor = settingsManager.settings.dynamicGlucoseColor displayXgridLines = settingsManager.settings.xGridLines displayYgridLines = settingsManager.settings.yGridLines thresholdLines = settingsManager.settings.rulerMarks @@ -423,6 +427,54 @@ extension Home { } } + private func getCurrentGlucoseTarget() async { + let now = Date() + let calendar = Calendar.current + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "HH:mm:ss" + dateFormatter.timeZone = TimeZone.current + + let bgTargets = await provider.getBGTarget() + let entries: [(start: String, value: Decimal)] = bgTargets.targets.map { ($0.start, $0.low) } + + for (index, entry) in entries.enumerated() { + guard let entryTime = dateFormatter.date(from: entry.start) else { + print("Invalid entry start time: \(entry.start)") + continue + } + + let entryComponents = calendar.dateComponents([.hour, .minute, .second], from: entryTime) + let entryStartTime = calendar.date( + bySettingHour: entryComponents.hour!, + minute: entryComponents.minute!, + second: entryComponents.second!, + of: now + )! + + let entryEndTime: Date + if index < entries.count - 1, + let nextEntryTime = dateFormatter.date(from: entries[index + 1].start) + { + let nextEntryComponents = calendar.dateComponents([.hour, .minute, .second], from: nextEntryTime) + entryEndTime = calendar.date( + bySettingHour: nextEntryComponents.hour!, + minute: nextEntryComponents.minute!, + second: nextEntryComponents.second!, + of: now + )! + } else { + entryEndTime = calendar.date(byAdding: .day, value: 1, to: entryStartTime)! + } + + if now >= entryStartTime, now < entryEndTime { + await MainActor.run { + currentGlucoseTarget = units == .mgdL ? entry.value : entry.value.asMmolL + } + return + } + } + } + func openCGM() { router.mainSecondaryModalView.send(router.view(for: .cgmDirect)) } @@ -467,8 +519,11 @@ extension Home.StateModel: smooth = settingsManager.settings.smoothGlucose lowGlucose = units == .mgdL ? settingsManager.settings.low : settingsManager.settings.low.asMmolL highGlucose = units == .mgdL ? settingsManager.settings.high : settingsManager.settings.high.asMmolL + Task { + await getCurrentGlucoseTarget() + } overrideUnit = settingsManager.settings.overrideHbA1cUnit - dynamicBGColor = settingsManager.settings.dynamicBGColor + dynamicGlucoseColor = settingsManager.settings.dynamicGlucoseColor displayXgridLines = settingsManager.settings.xGridLines displayYgridLines = settingsManager.settings.yGridLines thresholdLines = settingsManager.settings.rulerMarks diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index caf873e10..823141546 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -46,8 +46,9 @@ struct MainChartView: View { @Binding var smooth: Bool @Binding var highGlucose: Decimal @Binding var lowGlucose: Decimal + @Binding var currentGlucoseTarget: Decimal @Binding var screenHours: Int16 - @Binding var dynamicBGColor: Bool + @Binding var dynamicGlucoseColor: Bool @Binding var displayXgridLines: Bool @Binding var displayYgridLines: Bool @Binding var thresholdLines: Bool @@ -248,22 +249,26 @@ extension MainChartView { Chart { /// high and low threshold lines if thresholdLines { - let lowColor = setBGColor( - bgValue: lowGlucose, - highBGColorValue: highGlucose, - lowBGColorValue: lowGlucose, - dynamicBGColor: dynamicBGColor - ) - let highColor = setBGColor( - bgValue: highGlucose, - highBGColorValue: highGlucose, - lowBGColorValue: lowGlucose, - dynamicBGColor: dynamicBGColor - ) - RuleMark(y: .value("High", highGlucose)).foregroundStyle(highColor) - .lineStyle(.init(lineWidth: 1, dash: [5])) - RuleMark(y: .value("Low", lowGlucose)).foregroundStyle(lowColor) - .lineStyle(.init(lineWidth: 1, dash: [5])) + let lowColor = FreeAPS.getDynamicGlucoseColor( + glucoseValue: lowGlucose, + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: lowGlucose, + dynamicGlucoseColor: dynamicGlucoseColor, + offset: units == .mgdL ? 20 : 20.asMmolL + ) + let highColor = FreeAPS.getDynamicGlucoseColor( + glucoseValue: highGlucose, + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: highGlucose, + targetGlucose: highGlucose, + dynamicGlucoseColor: dynamicGlucoseColor, + offset: units == .mgdL ? 20 : 20.asMmolL + ) + RuleMark(y: .value("High", highGlucose)).foregroundStyle(highColor) + .lineStyle(.init(lineWidth: 1, dash: [5])) + RuleMark(y: .value("Low", lowGlucose)).foregroundStyle(lowColor) + .lineStyle(.init(lineWidth: 1, dash: [5])) } } .id("DummyMainChart") @@ -608,7 +613,7 @@ extension MainChartView { .foregroundStyle(Color.brown) } } - + private var stops: [Gradient.Stop] { let low = Double(lowGlucose) let high = Double(highGlucose) @@ -641,17 +646,19 @@ extension MainChartView { Gradient.Stop(color: .orange, location: 1.0) ] } - + private func drawGlucose(dummy _: Bool) -> some ChartContent { ForEach(state.glucoseFromPersistence) { item in let glucoseToDisplay = units == .mgdL ? Decimal(item.glucose) : Decimal(item.glucose).asMmolL - let color = setBGColor( - bgValue: glucoseLevel, - highBGColorValue: highGlucose, - lowBGColorValue: lowGlucose, - dynamicBGColor: dynamicBGColor + let dynamicColor = FreeAPS.getDynamicGlucoseColor( + glucoseValue: glucoseToDisplay, + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: currentGlucoseTarget, + dynamicGlucoseColor: dynamicGlucoseColor, + offset: units == .mgdL ? 20 : 20.asMmolL ) - + if smooth { LineMark(x: .value("Time", item.date ?? Date()), y: .value("Value", glucoseToDisplay)) .foregroundStyle( @@ -662,7 +669,7 @@ extension MainChartView { PointMark( x: .value("Time", item.date ?? Date(), unit: .second), y: .value("Value", glucoseToDisplay) - ).foregroundStyle(color).symbolSize(20) + ).foregroundStyle(dynamicColor).symbolSize(20) } } } diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index a8a59a002..521820973 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -372,8 +372,9 @@ extension Home { smooth: $state.smooth, highGlucose: $state.highGlucose, lowGlucose: $state.lowGlucose, + currentGlucoseTarget: $state.currentGlucoseTarget, screenHours: $state.hours, - dynamicBGColor: $state.dynamicBGColor, + dynamicGlucoseColor: $state.dynamicGlucoseColor, displayXgridLines: $state.displayXgridLines, displayYgridLines: $state.displayYgridLines, thresholdLines: $state.thresholdLines, diff --git a/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift b/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift index a6a314cae..fd170ce8b 100644 --- a/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift +++ b/FreeAPS/Sources/Modules/StatConfig/StatConfigStateModel.swift @@ -12,7 +12,7 @@ extension StatConfig { @Published var low: Decimal = 70 @Published var high: Decimal = 180 @Published var hours: Decimal = 6 - @Published var dynamicBGColor = false + @Published var dynamicGlucoseColor = false @Published var xGridLines = false @Published var yGridLines: Bool = false @Published var oneDimensionalGraph = false @@ -26,7 +26,7 @@ extension StatConfig { self.units = units subscribeSetting(\.overrideHbA1cUnit, on: $overrideHbA1cUnit) { overrideHbA1cUnit = $0 } - subscribeSetting(\.dynamicBGColor, on: $dynamicBGColor) { dynamicBGColor = $0 } + subscribeSetting(\.dynamicGlucoseColor, on: $dynamicGlucoseColor) { dynamicGlucoseColor = $0 } subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 } subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 } subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 } diff --git a/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift b/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift index 34083f3e7..ed22e6e59 100644 --- a/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift +++ b/FreeAPS/Sources/Modules/StatConfig/View/StatConfigRootView.swift @@ -45,7 +45,7 @@ extension StatConfig { var body: some View { Form { Section { - Toggle("Use Dynamic BG Color", isOn: $state.dynamicBGColor) + Toggle("Use Dynamic BG Color", isOn: $state.dynamicGlucoseColor) Toggle("Display Chart X - Grid lines", isOn: $state.xGridLines) Toggle("Display Chart Y - Grid lines", isOn: $state.yGridLines) Toggle("Display Chart Threshold lines for Low and High", isOn: $state.rulerMarks) diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift index 399a63668..3094974f3 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift @@ -20,7 +20,7 @@ struct LiveActivityAttributes: ActivityAttributes { let rotationDegrees: Double let highGlucose: Decimal let lowGlucose: Decimal - let dynamicBGColor: Bool + let dynamicGlucoseColor: Bool let cob: Decimal let iob: Decimal let unit: String diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift index 420bec3a3..0178ecd19 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift @@ -89,7 +89,7 @@ extension LiveActivityAttributes.ContentState { rotationDegrees: rotationDegrees, highGlucose: settings.high, lowGlucose: settings.low, - dynamicBGColor: settings.dynamicBGColor, + dynamicGlucoseColor: settings.dynamicGlucoseColor, cob: Decimal(determination?.cob ?? 0), iob: determination?.iob ?? 0 as Decimal, unit: settings.units.rawValue, diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 5403fa3f2..495902c13 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -179,7 +179,11 @@ struct LiveActivity: Widget { } } - private func bgAndTrend(context: ActivityViewContext, size: Size) -> (some View, Int) { + private func bgAndTrend( + context: ActivityViewContext, + size: Size, + dynamicColor _: Color + ) -> (some View, Int) { var characters = 0 let bgText = context.state.bg @@ -288,11 +292,13 @@ struct LiveActivity: Widget { y: .value("Value", displayValue) ).symbolSize(15) - let color = setBGColor( - bgValue: Int(currentValue), - highBGColorValue: Decimal(additionalState.highGlucose), - lowBGColorValue: Decimal(additionalState.lowGlucose), - dynamicBGColor: additionalState.dynamicBGColor + let color = getDynamicGlucoseColor( + glucoseValue: currentValue, + highGlucoseColorValue: additionalState.highGlucose, + lowGlucoseColorValue: additionalState.lowGlucose, + targetGlucose: 90, + dynamicGlucoseColor: additionalState.dynamicGlucoseColor, + offset: additionalState.unit == "mg/dL" ? 20 : 20.asMmolL ) pointMark.foregroundStyle(color) @@ -335,6 +341,15 @@ 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, + dynamicGlucoseColor: context.state.detailedViewState?.dynamicGlucoseColor ?? false, + offset: context.state.detailedViewState?.unit == "mg/dL" ? 20 : 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 { @@ -348,7 +363,7 @@ struct LiveActivity: Widget { } } else { HStack(spacing: 3) { - bgAndTrend(context: context, size: .expanded).0.font(.title) + bgAndTrend(context: context, size: .expanded, dynamicColor: glucoseColor).0.font(.title) Spacer() VStack(alignment: .trailing, spacing: 5) { changeLabel(context: context).font(.title3) @@ -369,14 +384,22 @@ struct LiveActivity: Widget { } func dynamicIsland(context: ActivityViewContext) -> DynamicIsland { - let bgValueForColor = Int(context.state.bg) ?? 100 + let glucoseValueForColor = context.state.bg let highGlucose = context.state.detailedViewState?.highGlucose ?? 180 let lowGlucose = context.state.detailedViewState?.lowGlucose ?? 70 - let dynamicBGColor = context.state.detailedViewState?.dynamicBGColor ?? false + let dynamicGlucoseColor = context.state.detailedViewState?.dynamicGlucoseColor ?? false + let glucoseColor = getDynamicGlucoseColor( + glucoseValue: Decimal(string: glucoseValueForColor) ?? 100, + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: 90, + dynamicGlucoseColor: dynamicGlucoseColor, + offset: context.state.detailedViewState?.unit == "mg/dL" ? 20 : 20.asMmolL + ) return DynamicIsland { DynamicIslandExpandedRegion(.leading) { - bgAndTrend(context: context, size: .expanded).0.font(.title2).padding(.leading, 5) + bgAndTrend(context: context, size: .expanded, dynamicColor: glucoseColor).0.font(.title2).padding(.leading, 5) } DynamicIslandExpandedRegion(.trailing) { changeLabel(context: context).font(.title2).padding(.trailing, 5) @@ -402,52 +425,11 @@ struct LiveActivity: Widget { } } } compactLeading: { - // bgAndTrend(context: context, size: .compact).0.padding(.leading, 4) - HStack(spacing: 1) { - Image(systemName: "drop.fill") - .renderingMode(.template) - .foregroundStyle(setBGColor( - bgValue: bgValueForColor, - highBGColorValue: Decimal(highGlucose), - lowBGColorValue: Decimal(lowGlucose), - dynamicBGColor: dynamicBGColor - )) - .baselineOffset(-2) - Text("\(context.state.bg)") - .foregroundStyle(setBGColor( - bgValue: bgValueForColor, - highBGColorValue: Decimal(highGlucose), - lowBGColorValue: Decimal(lowGlucose), - dynamicBGColor: dynamicBGColor - )) - .minimumScaleFactor(0.1) - .fontWeight(.bold) - } + bgAndTrend(context: context, size: .compact, dynamicColor: glucoseColor).0.padding(.leading, 4) } compactTrailing: { - // changeLabel(context: context).padding(.trailing, 4) - HStack(spacing: -5) { - Text("\(context.state.direction ?? "--")") - .foregroundStyle(setBGColor( - bgValue: bgValueForColor, - highBGColorValue: Decimal(highGlucose), - lowBGColorValue: Decimal(lowGlucose), - dynamicBGColor: dynamicBGColor - )) - .minimumScaleFactor(0.1) - .fontWeight(.bold) - .baselineOffset(-2) - Text("\(context.state.change)") - .foregroundStyle(setBGColor( - bgValue: bgValueForColor, - highBGColorValue: Decimal(highGlucose), - lowBGColorValue: Decimal(lowGlucose), - dynamicBGColor: dynamicBGColor - )) - .minimumScaleFactor(0.1) - .fontWeight(.bold) - } + changeLabel(context: context).padding(.trailing, 4) } minimal: { - let (_label, characterCount) = bgAndTrend(context: context, size: .minimal) + let (_label, characterCount) = bgAndTrend(context: context, size: .minimal, dynamicColor: glucoseColor) let label = _label.padding(.leading, 7).padding(.trailing, 3) if characterCount < 4 { @@ -482,7 +464,7 @@ private extension LiveActivityAttributes.ContentState { // Use mmol/l notation with decimal point as well for the same reason, it uses up to 4 characters, while mg/dl uses up to 3 static var testWide: LiveActivityAttributes.ContentState { LiveActivityAttributes.ContentState( - bg: "00.0", + bg: 00.0.description, direction: "→", change: "+0.0", date: Date(), diff --git a/Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved index 310890cf6..99dcafc98 100644 --- a/Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Trio.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "59ac7eba66375d6eb406e758cb0b9964f4b3b0ae45c5665596f00384c32262b9", + "originHash" : "f5c836c216c4ca7d356e3777e58d6d4f9502b03f3974891349eb775f4c4cf750", "pins" : [ { "identity" : "cryptoswift", @@ -49,7 +49,7 @@ { "identity" : "swiftcharts", "kind" : "remoteSourceControl", - "location" : "https://github.com/ivanschuetz/SwiftCharts.git", + "location" : "https://github.com/ivanschuetz/SwiftCharts", "state" : { "branch" : "master", "revision" : "c354c1945bb35a1f01b665b22474f6db28cba4a2" From f34afad0a00ea76f67d797e3e71d4b33d1c52be6 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Wed, 28 Aug 2024 21:53:25 +0200 Subject: [PATCH 08/17] Fix threshold line colors --- FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index 823141546..841cf1680 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -253,7 +253,7 @@ extension MainChartView { glucoseValue: lowGlucose, highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, - targetGlucose: lowGlucose, + targetGlucose: currentGlucoseTarget, dynamicGlucoseColor: dynamicGlucoseColor, offset: units == .mgdL ? 20 : 20.asMmolL ) @@ -261,7 +261,7 @@ extension MainChartView { glucoseValue: highGlucose, highGlucoseColorValue: highGlucose, lowGlucoseColorValue: highGlucose, - targetGlucose: highGlucose, + targetGlucose: currentGlucoseTarget, dynamicGlucoseColor: dynamicGlucoseColor, offset: units == .mgdL ? 20 : 20.asMmolL ) From b0e3ff806890dedc64e67077f18b43b0619bf807 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Wed, 28 Aug 2024 22:10:18 +0200 Subject: [PATCH 09/17] Increase offset for high glucose, so in-range glucose is green-ish for longer --- FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift | 2 +- FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift index 444724735..cd7785b64 100644 --- a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift +++ b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift @@ -13,7 +13,7 @@ public func getDynamicGlucoseColor( ) -> Color { // Convert Decimal to Int for high and low glucose values let lowGlucose = lowGlucoseColorValue - offset - let highGlucose = highGlucoseColorValue + offset + let highGlucose = highGlucoseColorValue + (offset * 1.75) let targetGlucose = targetGlucose // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index 841cf1680..fb67b4656 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -1229,8 +1229,8 @@ extension MainChartView { // Ensure maxForecast is not more than 100 over maxGlucose let adjustedMaxForecast = min(maxForecast, maxGlucose + 100) - var minOverall = min(minGlucose, minForecast) - var maxOverall = max(maxGlucose, adjustedMaxForecast) + let minOverall = min(minGlucose, minForecast) + let maxOverall = max(maxGlucose, adjustedMaxForecast) minValue = minOverall - 50 maxValue = maxOverall + 80 From d90c6e279a2dd11d77534b9d240f80a24d52b436 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 28 Sep 2024 02:54:21 +0200 Subject: [PATCH 10/17] Adjust broken build; various additions/changes * Rename and refactor boolean setting to type-based setting Glucose Color Scheme * Add setting to User Interface settings to pick scheme style * Various adjustments for proper display * Add dynamic coloring to forecast chart in treatment view * Fix broken build after merge (thanks to @polscm32) * Misc --- FreeAPS.xcodeproj/project.pbxproj | 8 ++--- .../defaults/freeaps/freeaps_settings.json | 2 +- .../Sources/Helpers/DynamicGlucoseColor.swift | 16 ++++----- FreeAPS/Sources/Models/FreeAPSSettings.swift | 6 ++-- ...orStyle.swift => GlucoseColorScheme.swift} | 6 ++-- .../Modules/Bolus/BolusStateModel.swift | 2 ++ .../Modules/Bolus/View/ForeCastChart.swift | 11 ++++-- .../Sources/Modules/Home/HomeStateModel.swift | 5 +-- .../Modules/Home/View/Chart/DummyCharts.swift | 10 +++--- .../Home/View/Chart/GlucoseChartView.swift | 4 +-- .../Home/View/Chart/MainChartView.swift | 6 ++-- .../Modules/Home/View/HomeRootView.swift | 2 +- .../UserInterfaceSettingsStateModel.swift | 4 +-- .../View/UserInterfaceSettingsRootView.swift | 36 +++++++++++++++++++ .../LiveActivity/LiveActitiyAttributes.swift | 2 +- .../LiveActivityAttributes+Helper.swift | 2 +- LiveActivity/LiveActivity.swift | 18 +++++----- 17 files changed, 94 insertions(+), 46 deletions(-) rename FreeAPS/Sources/Models/{GlucoseColorStyle.swift => GlucoseColorScheme.swift} (65%) diff --git a/FreeAPS.xcodeproj/project.pbxproj b/FreeAPS.xcodeproj/project.pbxproj index cca398cda..d6ad9ed11 100644 --- a/FreeAPS.xcodeproj/project.pbxproj +++ b/FreeAPS.xcodeproj/project.pbxproj @@ -449,7 +449,7 @@ DD6B7CBB2C7FBBFA00B75029 /* ReviewInsulinActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */; }; DD6D67E42C9C253500660C9B /* ColorSchemeOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */; }; DD88C8E22C50420800F2D558 /* DefinitionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD88C8E12C50420800F2D558 /* DefinitionRow.swift */; }; - DD940BAA2CA7585D000830A5 /* GlucoseColorStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD940BA92CA7585D000830A5 /* GlucoseColorStyle.swift */; }; + DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */; }; DD940BAC2CA75889000830A5 /* DynamicGlucoseColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD940BAB2CA75889000830A5 /* DynamicGlucoseColor.swift */; }; DDD163122C4C689900CD525A /* OverrideStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163112C4C689900CD525A /* OverrideStateModel.swift */; }; DDD163142C4C68D300CD525A /* OverrideProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD163132C4C68D300CD525A /* OverrideProvider.swift */; }; @@ -1114,7 +1114,7 @@ DD6B7CBA2C7FBBFA00B75029 /* ReviewInsulinActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewInsulinActionView.swift; sourceTree = ""; }; DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeOption.swift; sourceTree = ""; }; DD88C8E12C50420800F2D558 /* DefinitionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefinitionRow.swift; sourceTree = ""; }; - DD940BA92CA7585D000830A5 /* GlucoseColorStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseColorStyle.swift; sourceTree = ""; }; + DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseColorScheme.swift; sourceTree = ""; }; DD940BAB2CA75889000830A5 /* DynamicGlucoseColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicGlucoseColor.swift; sourceTree = ""; }; DDD163112C4C689900CD525A /* OverrideStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStateModel.swift; sourceTree = ""; }; DDD163132C4C68D300CD525A /* OverrideProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProvider.swift; sourceTree = ""; }; @@ -1916,7 +1916,7 @@ 388E5A5925B6F0250019842D /* Models */ = { isa = PBXGroup; children = ( - DD940BA92CA7585D000830A5 /* GlucoseColorStyle.swift */, + DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */, DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */, 385CEAC025F2EA52002D6D5B /* Announcement.swift */, 388E5A5F25B6F2310019842D /* Autosens.swift */, @@ -3334,7 +3334,7 @@ CEB434E728B9053300B70274 /* LoopUIColorPalette+Default.swift in Sources */, 19F95FF329F10FBC00314DDC /* StatDataFlow.swift in Sources */, 582DF97B2C8CE209001F516D /* CarbView.swift in Sources */, - DD940BAA2CA7585D000830A5 /* GlucoseColorStyle.swift in Sources */, + DD940BAA2CA7585D000830A5 /* GlucoseColorScheme.swift in Sources */, 3811DE2225C9D48300A708ED /* MainProvider.swift in Sources */, 3811DE0C25C9D32F00A708ED /* BaseProvider.swift in Sources */, CE95BF5A2BA62E4A00DC3DE3 /* PluginSource.swift in Sources */, diff --git a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json index 4fd654a63..293d4331f 100644 --- a/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json +++ b/FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json @@ -37,7 +37,7 @@ "high" : 180, "low" : 70, "hours" : 6, - "glucoseColorStyle" : "staticColor", + "glucoseColorScheme" : "staticColor", "xGridLines" : true, "yGridLines" : true, "oneDimensionalGraph" : false, diff --git a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift index 50e4918f0..83db4bf94 100644 --- a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift +++ b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift @@ -7,28 +7,28 @@ public func getDynamicGlucoseColor( highGlucoseColorValue: Decimal, lowGlucoseColorValue: Decimal, targetGlucose: Decimal, - glucoseColorStyle: GlucoseColorStyle, + glucoseColorScheme: GlucoseColorScheme, offset: Decimal ) -> Color { // Convert Decimal to Int for high and low glucose values - let lowGlucose = lowGlucoseColorValue - offset - let highGlucose = highGlucoseColorValue + (offset * 1.75) + let lowGlucose = lowGlucoseColorValue + let highGlucose = highGlucoseColorValue let targetGlucose = targetGlucose // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences - if GlucoseColorStyle == .dynamicColor { + if glucoseColorScheme == .dynamicColor { return calculateHueBasedGlucoseColor( glucoseValue: glucoseValue, - highGlucose: highGlucose, - lowGlucose: lowGlucose, + highGlucose: highGlucose + (offset * 1.75), + lowGlucose: lowGlucose - offset, targetGlucose: targetGlucose ) } // Otheriwse, use static (orange = high, red = low, green = range) else { - if glucoseValue > highGlucose { + if glucoseValue >= highGlucose { return Color.orange - } else if glucoseValue < lowGlucose { + } else if glucoseValue <= lowGlucose { return Color.red } else { return Color.green diff --git a/FreeAPS/Sources/Models/FreeAPSSettings.swift b/FreeAPS/Sources/Models/FreeAPSSettings.swift index 80de59f76..e138569c6 100644 --- a/FreeAPS/Sources/Models/FreeAPSSettings.swift +++ b/FreeAPS/Sources/Models/FreeAPSSettings.swift @@ -53,7 +53,7 @@ struct FreeAPSSettings: JSON, Equatable { var high: Decimal = 180 var low: Decimal = 70 var hours: Int = 6 - var glucoseColorStyle: GlucoseColorStyle = .staticColor + var glucoseColorScheme: GlucoseColorScheme = .staticColor var xGridLines: Bool = true var yGridLines: Bool = true var oneDimensionalGraph: Bool = false @@ -251,8 +251,8 @@ extension FreeAPSSettings: Decodable { settings.hours = hours } - if let glucoseColorStyle = try? container.decode(GlucoseColorStyle.self, forKey: .glucoseColorStyle) { - settings.glucoseColorStyle = glucoseColorStyle + if let glucoseColorScheme = try? container.decode(GlucoseColorScheme.self, forKey: .glucoseColorScheme) { + settings.glucoseColorScheme = glucoseColorScheme } if let xGridLines = try? container.decode(Bool.self, forKey: .xGridLines) { diff --git a/FreeAPS/Sources/Models/GlucoseColorStyle.swift b/FreeAPS/Sources/Models/GlucoseColorScheme.swift similarity index 65% rename from FreeAPS/Sources/Models/GlucoseColorStyle.swift rename to FreeAPS/Sources/Models/GlucoseColorScheme.swift index 4181bca51..977d8386b 100644 --- a/FreeAPS/Sources/Models/GlucoseColorStyle.swift +++ b/FreeAPS/Sources/Models/GlucoseColorScheme.swift @@ -1,13 +1,13 @@ // -// GlucoseColorStyle.swift +// GlucoseColorScheme.swift // FreeAPS // // Created by Cengiz Deniz on 27.09.24. // import Foundation -enum GlucoseColorStyle: String, JSON, CaseIterable, Identifiable, Codable, Hashable { - var id: String { rawValue } +public enum GlucoseColorScheme: String, JSON, CaseIterable, Identifiable, Codable, Hashable { + public var id: String { rawValue } case staticColor case dynamicColor diff --git a/FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift b/FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift index f6dbb070c..e6ce8dfdf 100644 --- a/FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift +++ b/FreeAPS/Sources/Modules/Bolus/BolusStateModel.swift @@ -20,6 +20,7 @@ extension Bolus { @Published var lowGlucose: Decimal = 70 @Published var highGlucose: Decimal = 180 + @Published var glucoseColorScheme: GlucoseColorScheme = .staticColor @Published var predictions: Predictions? @Published var amount: Decimal = 0 @@ -234,6 +235,7 @@ extension Bolus { maxProtein = settings.settings.maxProtein useFPUconversion = settingsManager.settings.useFPUconversion isSmoothingEnabled = settingsManager.settings.smoothGlucose + glucoseColorScheme = settingsManager.settings.glucoseColorScheme } private func getCurrentSettingValue(for type: SettingType) async { diff --git a/FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift b/FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift index 22103da62..84cc8440b 100644 --- a/FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift +++ b/FreeAPS/Sources/Modules/Bolus/View/ForeCastChart.swift @@ -122,9 +122,14 @@ struct ForeCastChart: View { private func drawGlucose() -> some ChartContent { ForEach(state.glucoseFromPersistence) { item in let glucoseToDisplay = state.units == .mgdL ? Decimal(item.glucose) : Decimal(item.glucose).asMmolL - let pointMarkColor: Color = glucoseToDisplay > state.highGlucose ? Color.orange : - glucoseToDisplay < state.lowGlucose ? Color.red : - Color.green + let pointMarkColor = FreeAPS.getDynamicGlucoseColor( + glucoseValue: glucoseToDisplay, + highGlucoseColorValue: state.highGlucose, + lowGlucoseColorValue: state.lowGlucose, + targetGlucose: (state.determination.first?.currentTarget ?? state.currentBGTarget as NSDecimalNumber) as Decimal, + glucoseColorScheme: state.glucoseColorScheme, + offset: units == .mgdL ? 20 : 20.asMmolL + ) if !state.isSmoothingEnabled { PointMark( diff --git a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift index 850e5b6da..7fbe3dde7 100644 --- a/FreeAPS/Sources/Modules/Home/HomeStateModel.swift +++ b/FreeAPS/Sources/Modules/Home/HomeStateModel.swift @@ -51,7 +51,7 @@ extension Home { @Published var highGlucose: Decimal = 180 @Published var currentGlucoseTarget: Decimal = 100 @Published var overrideUnit: Bool = false - @Published var glucoseColorStyle: GlucoseColorStyle = .staticColor + @Published var glucoseColorScheme: GlucoseColorScheme = .staticColor @Published var displayXgridLines: Bool = false @Published var displayYgridLines: Bool = false @Published var thresholdLines: Bool = false @@ -328,6 +328,7 @@ extension Home { manualTempBasal = apsManager.isManualTempBasal setupCurrentTempTarget() isSmoothingEnabled = settingsManager.settings.smoothGlucose + glucoseColorScheme = settingsManager.settings.glucoseColorScheme maxValue = settingsManager.preferences.autosensMax lowGlucose = units == .mgdL ? settingsManager.settings.low : settingsManager.settings.low.asMmolL highGlucose = units == .mgdL ? settingsManager.settings.high : settingsManager.settings.high.asMmolL @@ -588,7 +589,7 @@ extension Home.StateModel: await getCurrentGlucoseTarget() } overrideUnit = settingsManager.settings.overrideHbA1cUnit - glucoseColorStyle = settingsManager.settings.glucoseColorStyle + glucoseColorScheme = settingsManager.settings.glucoseColorScheme displayXgridLines = settingsManager.settings.xGridLines displayYgridLines = settingsManager.settings.yGridLines thresholdLines = settingsManager.settings.rulerMarks diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift b/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift index 7730d995a..f36bce117 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift @@ -13,7 +13,7 @@ extension MainChartView { highGlucoseColorValue: highGlucose, lowGlucoseColorValue: highGlucose, targetGlucose: currentGlucoseTarget, - glucoseColorStyle: glucoseColorStyle, + glucoseColorScheme: glucoseColorScheme, offset: units == .mgdL ? 20 : 20.asMmolL ) let lowColor = FreeAPS.getDynamicGlucoseColor( @@ -21,13 +21,15 @@ extension MainChartView { highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, targetGlucose: currentGlucoseTarget, - glucoseColorStyle: glucoseColorStyle, + glucoseColorScheme: glucoseColorScheme, offset: units == .mgdL ? 20 : 20.asMmolL ) - RuleMark(y: .value("High", highGlucose)).foregroundStyle(highColor) + RuleMark(y: .value("High", highGlucose)) + .foregroundStyle(highColor) .lineStyle(.init(lineWidth: 1, dash: [5])) - RuleMark(y: .value("Low", lowGlucose)).foregroundStyle(lowColor) + RuleMark(y: .value("Low", lowGlucose)) + .foregroundStyle(lowColor) .lineStyle(.init(lineWidth: 1, dash: [5])) } } diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift index dc6b96ae6..1daf20730 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift @@ -9,7 +9,7 @@ struct GlucoseChartView: ChartContent { let lowGlucose: Decimal let currentGlucoseTarget: Decimal let isSmoothingEnabled: Bool - let glucoseColorStyle: GlucoseColorStyle + let glucoseColorScheme: GlucoseColorScheme var body: some ChartContent { drawGlucoseChart() @@ -24,7 +24,7 @@ struct GlucoseChartView: ChartContent { highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, targetGlucose: currentGlucoseTarget, - glucoseColorStyle: glucoseColorStyle, + glucoseColorScheme: glucoseColorScheme, offset: units == .mgdL ? 20 : 20.asMmolL ) diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift index 1ebf8db60..09dd8d385 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/MainChartView.swift @@ -14,7 +14,7 @@ struct MainChartView: View { @Binding var lowGlucose: Decimal @Binding var currentGlucoseTarget: Decimal @Binding var screenHours: Int16 - @Binding var glucoseColorStyle: GlucoseColorStyle + @Binding var glucoseColorScheme: GlucoseColorScheme @Binding var displayXgridLines: Bool @Binding var displayYgridLines: Bool @Binding var thresholdLines: Bool @@ -145,7 +145,7 @@ extension MainChartView { lowGlucose: state.lowGlucose, currentGlucoseTarget: state.currentGlucoseTarget, isSmoothingEnabled: state.isSmoothingEnabled, - glucoseColorStyle: state.glucoseColorStyle + glucoseColorScheme: state.glucoseColorScheme ) InsulinView( @@ -257,7 +257,7 @@ extension MainChartView { highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, targetGlucose: currentGlucoseTarget, - glucoseColorStyle: glucoseColorStyle, + glucoseColorScheme: glucoseColorScheme, offset: units == .mgdL ? 20 : 20.asMmolL ) HStack { diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 1b864ee36..07181f255 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -343,7 +343,7 @@ extension Home { lowGlucose: $state.lowGlucose, currentGlucoseTarget: $state.currentGlucoseTarget, screenHours: $state.hours, - glucoseColorStyle: $state.glucoseColorStyle, + glucoseColorScheme: $state.glucoseColorScheme, displayXgridLines: $state.displayXgridLines, displayYgridLines: $state.displayYgridLines, thresholdLines: $state.thresholdLines, diff --git a/FreeAPS/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift b/FreeAPS/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift index bf940c6d7..a8ad150e5 100644 --- a/FreeAPS/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift +++ b/FreeAPS/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift @@ -14,7 +14,7 @@ extension UserInterfaceSettings { @Published var totalInsulinDisplayType: TotalInsulinDisplayType = .totalDailyDose @Published var showCarbsRequiredBadge: Bool = true @Published var carbsRequiredThreshold: Decimal = 0 - @Published var glucoseColorStyle: GlucoseColorStyle = .staticColor + @Published var glucoseColorScheme: GlucoseColorScheme = .staticColor var units: GlucoseUnits = .mgdL @@ -43,7 +43,7 @@ extension UserInterfaceSettings { on: $carbsRequiredThreshold ) { carbsRequiredThreshold = $0 } - subscribeSetting(\.glucoseColorStyle, on: $glucoseColorStyle) { glucoseColorStyle = $0 } + subscribeSetting(\.glucoseColorScheme, on: $glucoseColorScheme) { glucoseColorScheme = $0 } } } } diff --git a/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift b/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift index 07e2b9392..1967cffe9 100644 --- a/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift +++ b/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift @@ -93,6 +93,42 @@ extension UserInterfaceSettings { } ).listRowBackground(Color.chart) + Section { + VStack { + Picker( + selection: $state.glucoseColorScheme, + label: Text("Glucose Color Scheme") + ) { + ForEach(GlucoseColorScheme.allCases) { selection in + Text(selection.displayName).tag(selection) + } + }.padding(.top) + + HStack(alignment: .top) { + Text( + "Glucose Scheme Preference ... dynamic or static ... Lorem ipsum dolor" + ) + .font(.footnote) + .foregroundColor(.secondary) + .lineLimit(nil) + Spacer() + Button( + action: { + hintLabel = "Glucose Scheme Preference" + selectedVerboseHint = + "Glucose Scheme Preference... Lorem ipsum dolor sit amet, consetetur sadipscing elitr." + shouldDisplayHint.toggle() + }, + label: { + HStack { + Image(systemName: "questionmark.circle") + } + } + ).buttonStyle(BorderlessButtonStyle()) + }.padding(.top) + }.padding(.bottom) + }.listRowBackground(Color.chart) + Section( header: Text("Home View Settings"), content: { diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift index 00cd3a712..d96f2223f 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift @@ -20,7 +20,7 @@ struct LiveActivityAttributes: ActivityAttributes { let rotationDegrees: Double let highGlucose: Decimal let lowGlucose: Decimal - let glucoseColorStyle: String + let glucoseColorScheme: String let cob: Decimal let iob: Decimal let unit: String diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift index 494b6cb2a..d8337ac57 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift +++ b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift @@ -89,7 +89,7 @@ extension LiveActivityAttributes.ContentState { rotationDegrees: rotationDegrees, highGlucose: settings.high, lowGlucose: settings.low, - glucoseColorStyle: settings.glucoseColorStyle.rawValue, + glucoseColorScheme: settings.glucoseColorScheme.rawValue, cob: Decimal(determination?.cob ?? 0), iob: determination?.iob ?? 0 as Decimal, unit: settings.units.rawValue, diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 6207eb1a7..13f6c39a9 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -17,9 +17,9 @@ enum GlucoseUnits: String, Equatable { static let exchangeRate: Decimal = 0.0555 } -enum GlucoseColorStyle: String, Equatable { - case staticColor = "staticColor" - case dynamicColor = "dynamicColor" +enum GlucoseColorScheme: String, Equatable { + case staticColor + case dynamicColor } // Helper function to decide how to pick the glucose color @@ -28,16 +28,17 @@ func getDynamicGlucoseColor( highGlucoseColorValue: Decimal, lowGlucoseColorValue: Decimal, targetGlucose: Decimal, - glucoseColorStyle: GlucoseColorStyle, + 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 glucoseColorStyle == .dynamicColor { + if glucoseColorScheme == "dynamicColor" { return calculateHueBasedGlucoseColor( glucoseValue: glucoseValue, highGlucose: highGlucose, @@ -372,7 +373,7 @@ struct LiveActivity: Widget { highGlucoseColorValue: additionalState.highGlucose, lowGlucoseColorValue: additionalState.lowGlucose, targetGlucose: 90, - glucoseColorStyle: additionalState.glucoseColorStyle ?? "staticColor", + glucoseColorScheme: additionalState.glucoseColorScheme ?? "staticColor", offset: additionalState.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL ) @@ -421,7 +422,7 @@ struct LiveActivity: Widget { highGlucoseColorValue: context.state.detailedViewState?.highGlucose ?? 180, lowGlucoseColorValue: context.state.detailedViewState?.lowGlucose ?? 70, targetGlucose: 90, - glucoseColorStyle: context.state.detailedViewState?.glucoseColorStyle ?? "staticColor", + glucoseColorScheme: context.state.detailedViewState?.glucoseColorScheme ?? "staticColor", offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL ) @@ -467,7 +468,7 @@ struct LiveActivity: Widget { highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, targetGlucose: 90, - glucoseColorStyle: context.state.detailedViewState?.glucoseColorStyle ?? "staticColor", + glucoseColorScheme: context.state.detailedViewState?.glucoseColorScheme ?? "staticColor", offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL ) @@ -525,6 +526,7 @@ struct LiveActivity: Widget { ActivityConfiguration(for: LiveActivityAttributes.self, content: self.content, dynamicIsland: self.dynamicIsland) } } + private extension LiveActivityAttributes { static var preview: LiveActivityAttributes { LiveActivityAttributes(startDate: Date()) From eb5fd45e180586f7cc3869a3a13c715828b6ebfa Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 28 Sep 2024 02:57:55 +0200 Subject: [PATCH 11/17] Misc. : * Make app color scheme and glucose color scheme searchable * Small label typo fixes --- FreeAPS/Sources/Modules/Settings/SettingItems.swift | 4 +++- .../View/UserInterfaceSettingsRootView.swift | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/FreeAPS/Sources/Modules/Settings/SettingItems.swift b/FreeAPS/Sources/Modules/Settings/SettingItems.swift index 81f9b0b7b..66506b00c 100644 --- a/FreeAPS/Sources/Modules/Settings/SettingItems.swift +++ b/FreeAPS/Sources/Modules/Settings/SettingItems.swift @@ -191,7 +191,9 @@ enum SettingItems { "Standing / Laying TIR Chart", "Show Carbs Required Badge", "Carbs Required Threshold", - "Forecast Display Type" + "Forecast Display Type", + "Trio Color Scheme", + "Glucose Color Scheme" ], path: ["Features", "User Interface"] ), diff --git a/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift b/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift index 1967cffe9..8133f535a 100644 --- a/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift +++ b/FreeAPS/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift @@ -61,7 +61,7 @@ extension UserInterfaceSettings { VStack { Picker( selection: $colorSchemePreference, - label: Text("Color Scheme") + label: Text("Trio Color Scheme") ) { ForEach(ColorSchemeOption.allCases) { selection in Text(selection.displayName).tag(selection) @@ -106,7 +106,7 @@ extension UserInterfaceSettings { HStack(alignment: .top) { Text( - "Glucose Scheme Preference ... dynamic or static ... Lorem ipsum dolor" + "Glucose Color Scheme ... dynamic or static ... Lorem ipsum dolor" ) .font(.footnote) .foregroundColor(.secondary) @@ -114,9 +114,9 @@ extension UserInterfaceSettings { Spacer() Button( action: { - hintLabel = "Glucose Scheme Preference" + hintLabel = "Glucose Color Scheme" selectedVerboseHint = - "Glucose Scheme Preference... Lorem ipsum dolor sit amet, consetetur sadipscing elitr." + "Glucose Color Scheme... Lorem ipsum dolor sit amet, consetetur sadipscing elitr." shouldDisplayHint.toggle() }, label: { From ad007829a6ed96a0d35ee8d97af1ea92de90822b Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 28 Sep 2024 03:10:02 +0200 Subject: [PATCH 12/17] Make BG bobble glucose value color dynamic (depending on setting) --- .../Home/View/Header/CurrentGlucoseView.swift | 27 +++++++------------ .../Modules/Home/View/HomeRootView.swift | 2 ++ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift index 972300e9a..13294ce29 100644 --- a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift @@ -8,6 +8,8 @@ struct CurrentGlucoseView: View { @Binding var lowGlucose: Decimal @Binding var highGlucose: Decimal @Binding var cgmAvailable: Bool + @Binding var currentGlucoseTarget: Decimal + @Binding var glucoseColorScheme: GlucoseColorScheme var glucose: [GlucoseStored] // This contains the last two glucose values, no matter if its manual or a cgm reading @@ -163,12 +165,6 @@ struct CurrentGlucoseView: View { var glucoseDisplayColor: Color { guard let lastGlucose = glucose.last?.glucose else { return .primary } - // Convert the lastest glucose value to Int for comparison - let whichGlucose = Int(lastGlucose) - - // Define default color based on the color scheme - let defaultColor: Color = colorScheme == .dark ? .white : .black - // low and high glucose is parsed in state to mmol/L; parse it back to mg/dl here for comparison let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL @@ -176,17 +172,14 @@ struct CurrentGlucoseView: View { // Ensure the thresholds are logical guard lowGlucose < highGlucose else { return .primary } - // Perform range checks using Int converted values - switch whichGlucose { - case 0 ..< Int(lowGlucose): - return .loopRed - case Int(lowGlucose) ..< Int(highGlucose): - return defaultColor - case Int(highGlucose)...: - return .loopYellow - default: - return defaultColor - } + return FreeAPS.getDynamicGlucoseColor( + glucoseValue: Decimal(lastGlucose), + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: currentGlucoseTarget, + glucoseColorScheme: glucoseColorScheme, + offset: units == .mgdL ? 20 : 20.asMmolL + ) } } diff --git a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift index 07181f255..720dca3a4 100644 --- a/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift +++ b/FreeAPS/Sources/Modules/Home/View/HomeRootView.swift @@ -136,6 +136,8 @@ extension Home { lowGlucose: $state.lowGlucose, highGlucose: $state.highGlucose, cgmAvailable: $state.cgmAvailable, + currentGlucoseTarget: $state.currentGlucoseTarget, + glucoseColorScheme: $state.glucoseColorScheme, glucose: state.latestTwoGlucoseValues ).scaleEffect(0.9) .onTapGesture { From d9725ea9e35fc04add441c18a523d68eb214fbf4 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sat, 28 Sep 2024 22:40:17 +0200 Subject: [PATCH 13/17] Adjust BG bobble color to primary; make dynamic work for LA+dynamic island --- .../Home/View/Header/CurrentGlucoseView.swift | 2 + .../LiveActivity/LiveActitiyAttributes.swift | 7 +- .../LiveActivityAttributes+Helper.swift | 6 +- .../LiveActivity/LiveActivityBridge.swift | 3 + LiveActivity/LiveActivity.swift | 259 ++++++++++-------- 5 files changed, 158 insertions(+), 119 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift index 13294ce29..25d1c5b33 100644 --- a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift +++ b/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, diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift index d96f2223f..103ee813c 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActitiyAttributes.swift +++ b/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 diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift index d8337ac57..308807549 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActivityAttributes+Helper.swift +++ b/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 ) diff --git a/FreeAPS/Sources/Services/LiveActivity/LiveActivityBridge.swift b/FreeAPS/Sources/Services/LiveActivity/LiveActivityBridge.swift index 96ba31d09..cede41a15 100644 --- a/FreeAPS/Sources/Services/LiveActivity/LiveActivityBridge.swift +++ b/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 ), diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 13f6c39a9..eec0e915a 100644 --- a/LiveActivity/LiveActivity.swift +++ b/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, 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, - 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) -> 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) -> 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 ) From 27c8c4ddc34ea17d914c34fb6065eb727146f499 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sun, 29 Sep 2024 00:53:16 +0200 Subject: [PATCH 14/17] Small adjustments + fix render issue by doing it all in mg/dL --- .../Sources/Helpers/DynamicGlucoseColor.swift | 13 +--- .../Modules/Bolus/View/ForecastChart.swift | 28 ++++--- .../Home/View/Chart/GlucoseChartView.swift | 13 +++- .../Home/View/Header/CurrentGlucoseView.swift | 77 ++++++++++++------- 4 files changed, 78 insertions(+), 53 deletions(-) diff --git a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift index 83db4bf94..b1c8677e8 100644 --- a/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift +++ b/FreeAPS/Sources/Helpers/DynamicGlucoseColor.swift @@ -10,25 +10,20 @@ public func getDynamicGlucoseColor( glucoseColorScheme: GlucoseColorScheme, offset: Decimal ) -> Color { - // Convert Decimal to Int for high and low glucose values - let lowGlucose = lowGlucoseColorValue - let highGlucose = highGlucoseColorValue - let targetGlucose = targetGlucose - // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences if glucoseColorScheme == .dynamicColor { return calculateHueBasedGlucoseColor( glucoseValue: glucoseValue, - highGlucose: highGlucose + (offset * 1.75), - lowGlucose: lowGlucose - offset, + highGlucose: highGlucoseColorValue + (offset * 1.75), + lowGlucose: lowGlucoseColorValue - offset, targetGlucose: targetGlucose ) } // Otheriwse, use static (orange = high, red = low, green = range) else { - if glucoseValue >= highGlucose { + if glucoseValue >= highGlucoseColorValue { return Color.orange - } else if glucoseValue <= lowGlucose { + } else if glucoseValue <= lowGlucoseColorValue { return Color.red } else { return Color.green diff --git a/FreeAPS/Sources/Modules/Bolus/View/ForecastChart.swift b/FreeAPS/Sources/Modules/Bolus/View/ForecastChart.swift index 6eef5b902..a5aab4cdb 100644 --- a/FreeAPS/Sources/Modules/Bolus/View/ForecastChart.swift +++ b/FreeAPS/Sources/Modules/Bolus/View/ForecastChart.swift @@ -116,13 +116,19 @@ struct ForecastChart: View { private func drawGlucose() -> some ChartContent { ForEach(state.glucoseFromPersistence) { item in let glucoseToDisplay = state.units == .mgdL ? Decimal(item.glucose) : Decimal(item.glucose).asMmolL - let pointMarkColor = FreeAPS.getDynamicGlucoseColor( - glucoseValue: glucoseToDisplay, - highGlucoseColorValue: state.highGlucose, - lowGlucoseColorValue: state.lowGlucose, - targetGlucose: (state.determination.first?.currentTarget ?? state.currentBGTarget as NSDecimalNumber) as Decimal, + + // low and high glucose is parsed in state to mmol/L; parse it back to mg/dl here for comparison + let lowGlucose = units == .mgdL ? state.lowGlucose : state.lowGlucose.asMgdL + let highGlucose = units == .mgdL ? state.highGlucose : state.highGlucose.asMgdL + let targetGlucose = (state.determination.first?.currentTarget ?? state.currentBGTarget as NSDecimalNumber) as Decimal + + let pointMarkColor: Color = FreeAPS.getDynamicGlucoseColor( + glucoseValue: Decimal(item.glucose), + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: targetGlucose, glucoseColorScheme: state.glucoseColorScheme, - offset: units == .mgdL ? 20 : 20.asMmolL + offset: 20 ) if !state.isSmoothingEnabled { @@ -131,7 +137,7 @@ struct ForecastChart: View { y: .value("Value", glucoseToDisplay) ) .foregroundStyle(pointMarkColor) - .symbolSize(20) + .symbolSize(18) } else { PointMark( x: .value("Time", item.date ?? Date(), unit: .second), @@ -139,7 +145,7 @@ struct ForecastChart: View { ) .symbol { Image(systemName: "record.circle.fill") - .font(.system(size: 8)) + .font(.system(size: 6)) .bold() .foregroundStyle(pointMarkColor) } @@ -231,8 +237,8 @@ struct ForecastChart: View { AxisMarks(values: .stride(by: .hour, count: 2)) { _ in AxisGridLine(stroke: .init(lineWidth: 0.5, dash: [2, 3])) AxisValueLabel(format: .dateTime.hour(.defaultDigits(amPM: .narrow)), anchor: .top) - .font(.footnote) - .foregroundStyle(Color.primary) + .font(.caption2) + .foregroundStyle(Color.secondary) } } @@ -240,7 +246,7 @@ struct ForecastChart: View { AxisMarks(position: .trailing) { _ in AxisGridLine(stroke: .init(lineWidth: 0.5, dash: [2, 3])) AxisTick(length: 3, stroke: .init(lineWidth: 3)).foregroundStyle(Color.secondary) - AxisValueLabel().font(.footnote).foregroundStyle(Color.primary) + AxisValueLabel().font(.caption2).foregroundStyle(Color.secondary) } } } diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift index 1daf20730..e609926fd 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift @@ -19,13 +19,18 @@ struct GlucoseChartView: ChartContent { ForEach(glucoseData) { item in let glucoseToDisplay = units == .mgdL ? Decimal(item.glucose) : Decimal(item.glucose).asMmolL - let pointMarkColor = FreeAPS.getDynamicGlucoseColor( - glucoseValue: glucoseToDisplay, + // low glucose, high glucose and target is parsed in state to mmol/L; parse it back to mg/dl here for comparison + let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL + let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL + let targetGlucose = units == .mgdL ? currentGlucoseTarget : currentGlucoseTarget.asMgdL + + let pointMarkColor: Color = FreeAPS.getDynamicGlucoseColor( + glucoseValue: Decimal(item.glucose), highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, - targetGlucose: currentGlucoseTarget, + targetGlucose: targetGlucose, glucoseColorScheme: glucoseColorScheme, - offset: units == .mgdL ? 20 : 20.asMmolL + offset: 20 ) if !isSmoothingEnabled { diff --git a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift index 25d1c5b33..ff979a4fb 100644 --- a/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift @@ -81,15 +81,34 @@ struct CurrentGlucoseView: View { if let glucoseValue = glucose.last?.glucose { let displayGlucose = units == .mgdL ? Decimal(glucoseValue).description : Decimal(glucoseValue) .formattedAsMmolL - Text( + + // low glucose, high glucose and target is parsed in state to mmol/L; parse it back to mg/dl here for comparison + let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL + let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL + let targetGlucose = units == .mgdL ? currentGlucoseTarget : currentGlucoseTarget.asMgdL + + var glucoseDisplayColor = Color.primary + + if Decimal(glucoseValue) <= lowGlucose || Decimal(glucoseValue) >= highGlucose { + glucoseDisplayColor = FreeAPS.getDynamicGlucoseColor( + glucoseValue: Decimal(glucoseValue), + highGlucoseColorValue: highGlucose, + lowGlucoseColorValue: lowGlucose, + targetGlucose: targetGlucose, + glucoseColorScheme: glucoseColorScheme, + offset: 20 + ) + } + + return Text( glucoseValue == 400 ? "HIGH" : displayGlucose ) .font(.system(size: 40, weight: .bold, design: .rounded)) - .foregroundColor(alarm == nil ? glucoseDisplayColor : .loopRed) + .foregroundStyle(glucoseDisplayColor) } else { - Text("--") + return Text("--") .font(.system(size: 40, weight: .bold, design: .rounded)) - .foregroundColor(.secondary) + .foregroundStyle(.secondary) } } HStack { @@ -101,18 +120,18 @@ struct CurrentGlucoseView: View { NSLocalizedString("min", comment: "Short form for minutes") + " " ) ) - .font(.caption2).foregroundColor(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary) + .font(.caption2).foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary) Text( delta ) - .font(.caption2).foregroundColor(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary) + .font(.caption2).foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary) }.frame(alignment: .top) } } - .onChange(of: glucose.last?.directionEnum) { newDirection in + .onChange(of: glucose.last?.directionEnum) { withAnimation { - switch newDirection { + switch glucose.last?.directionEnum { case .doubleUp, .singleUp, .tripleUp: @@ -162,27 +181,27 @@ struct CurrentGlucoseView: View { return deltaFormatter.string(from: deltaAsDecimal as NSNumber) ?? "--" } - var glucoseDisplayColor: Color { - guard let lastGlucose = glucose.last?.glucose else { return .primary } - - // low and high glucose is parsed in state to mmol/L; parse it back to mg/dl here for comparison - let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL - let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL - - // 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, - lowGlucoseColorValue: lowGlucose, - targetGlucose: currentGlucoseTarget, - glucoseColorScheme: glucoseColorScheme, - offset: units == .mgdL ? 20 : 20.asMmolL - ) - } +// var glucoseDisplayColor: Color { +// guard let lastGlucose = glucose.last?.glucose else { return .primary } +// +// // low and high glucose is parsed in state to mmol/L; parse it back to mg/dl here for comparison +// let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL +// let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL +// +// // 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, +// lowGlucoseColorValue: lowGlucose, +// targetGlucose: currentGlucoseTarget, +// glucoseColorScheme: glucoseColorScheme, +// offset: 20 +// ) +// } } struct Triangle: Shape { From a6a1b08e09cbbe8193a197a646219bfd1e81619e Mon Sep 17 00:00:00 2001 From: polscm32 <107251660+polscm32@users.noreply.github.com> Date: Sun, 29 Sep 2024 02:14:31 +0200 Subject: [PATCH 15/17] Fix color bug when using dynamic bg color --- .../Sources/Modules/Home/View/Chart/GlucoseChartView.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift index e609926fd..15bef590d 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/GlucoseChartView.swift @@ -19,16 +19,15 @@ struct GlucoseChartView: ChartContent { ForEach(glucoseData) { item in let glucoseToDisplay = units == .mgdL ? Decimal(item.glucose) : Decimal(item.glucose).asMmolL - // low glucose, high glucose and target is parsed in state to mmol/L; parse it back to mg/dl here for comparison + // low glucose and high glucose is parsed in state to mmol/L; parse it back to mg/dL here for comparison let lowGlucose = units == .mgdL ? lowGlucose : lowGlucose.asMgdL let highGlucose = units == .mgdL ? highGlucose : highGlucose.asMgdL - let targetGlucose = units == .mgdL ? currentGlucoseTarget : currentGlucoseTarget.asMgdL let pointMarkColor: Color = FreeAPS.getDynamicGlucoseColor( glucoseValue: Decimal(item.glucose), highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, - targetGlucose: targetGlucose, + targetGlucose: currentGlucoseTarget, glucoseColorScheme: glucoseColorScheme, offset: 20 ) From 6d150361e87017ac0ac6a8e4bdff4faae188ffd5 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sun, 29 Sep 2024 16:41:50 +0200 Subject: [PATCH 16/17] Fix conversion and coloring issue for LA and threshold RulerMarks --- .../Modules/Home/View/Chart/DummyCharts.swift | 8 +-- LiveActivity/LiveActivity.swift | 68 +++++++++++++++---- 2 files changed, 57 insertions(+), 19 deletions(-) diff --git a/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift b/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift index f36bce117..9025ca67d 100644 --- a/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift +++ b/FreeAPS/Sources/Modules/Home/View/Chart/DummyCharts.swift @@ -12,17 +12,17 @@ extension MainChartView { glucoseValue: highGlucose, highGlucoseColorValue: highGlucose, lowGlucoseColorValue: highGlucose, - targetGlucose: currentGlucoseTarget, + targetGlucose: units == .mgdL ? currentGlucoseTarget : currentGlucoseTarget.asMmolL, glucoseColorScheme: glucoseColorScheme, - offset: units == .mgdL ? 20 : 20.asMmolL + offset: units == .mgdL ? Decimal(20) : Decimal(20).asMmolL ) let lowColor = FreeAPS.getDynamicGlucoseColor( glucoseValue: lowGlucose, highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, - targetGlucose: currentGlucoseTarget, + targetGlucose: units == .mgdL ? currentGlucoseTarget : currentGlucoseTarget.asMmolL, glucoseColorScheme: glucoseColorScheme, - offset: units == .mgdL ? 20 : 20.asMmolL + offset: units == .mgdL ? Decimal(20) : Decimal(20).asMmolL ) RuleMark(y: .value("High", highGlucose)) diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index eec0e915a..904d1e156 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -79,6 +79,13 @@ struct LiveActivity: Widget { let highGlucose = highGlucoseColorValue + (offset * 1.75) let targetGlucose = targetGlucose + print("glucoseValue: \(glucoseValue)") + print("lowGlucose: \(lowGlucose)") + print("highGlucose: \(highGlucose)") + print("targetGlucose: \(targetGlucose)") + print("glucoseColorScheme: \(glucoseColorScheme)") + print("offset: \(offset)") + // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences if glucoseColorScheme == "dynamicColor" { return calculateHueBasedGlucoseColor( @@ -268,16 +275,11 @@ struct LiveActivity: Widget { // narrow mode is for the minimal dynamic island view // there is not enough space to show all three arrow there // and everything has to be squeezed together to some degree - // only display the first arrow character and make it red in case there were more characters + // only display the first arrow character var directionText: String? - var warnColor: Color? if let direction = context.state.direction { if size == .compact { directionText = String(direction[direction.startIndex ... direction.startIndex]) - - if direction.count > 1 { - warnColor = Color.red - } } else { directionText = direction } @@ -337,8 +339,7 @@ struct LiveActivity: Widget { @ViewBuilder func chart( context: ActivityViewContext, - additionalState: LiveActivityAttributes.ContentAdditionalState, - glucoseColor: Color + additionalState: LiveActivityAttributes.ContentAdditionalState ) -> some View { if context.isStale { Text("No data available") @@ -352,22 +353,56 @@ struct LiveActivity: Widget { let yAxisRuleMarkMax = additionalState.unit == "mg/dL" ? context.state.highGlucose : context.state.highGlucose .asMmolL + // TODO: grab target from proper targets, do not hard code. + let highColor = getDynamicGlucoseColor( + glucoseValue: yAxisRuleMarkMax, + highGlucoseColorValue: yAxisRuleMarkMax, + lowGlucoseColorValue: yAxisRuleMarkMin, + targetGlucose: additionalState.unit == "mg/dL" ? Decimal(90) : Decimal(90).asMmolL, + glucoseColorScheme: context.state.glucoseColorScheme, + offset: additionalState.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL + ) + + // TODO: grab target from proper targets, do not hard code. + let lowColor = getDynamicGlucoseColor( + glucoseValue: yAxisRuleMarkMin, + highGlucoseColorValue: yAxisRuleMarkMax, + lowGlucoseColorValue: yAxisRuleMarkMin, + targetGlucose: additionalState.unit == "mg/dL" ? Decimal(90) : Decimal(90).asMmolL, + glucoseColorScheme: context.state.glucoseColorScheme, + offset: additionalState.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL + ) + Chart { - RuleMark(y: .value("Low", yAxisRuleMarkMin)) - .lineStyle(.init(lineWidth: 0.5, dash: [5])) RuleMark(y: .value("High", yAxisRuleMarkMax)) + .foregroundStyle(highColor) + .lineStyle(.init(lineWidth: 0.5, dash: [5])) + RuleMark(y: .value("Low", yAxisRuleMarkMin)) + .foregroundStyle(lowColor) .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 + + // TODO: grab target from proper targets, do not hard code. + let pointMarkColor = self.getDynamicGlucoseColor( + glucoseValue: currentValue, + highGlucoseColorValue: context.state.highGlucose, + lowGlucoseColorValue: context.state.lowGlucose, + targetGlucose: 90, + glucoseColorScheme: context.state.glucoseColorScheme, + offset: 20 + ) + let chartDate = additionalState.chartDate[index] ?? Date() + let pointMark = PointMark( x: .value("Time", chartDate), y: .value("Value", displayValue) ).symbolSize(15) - pointMark.foregroundStyle(glucoseColor) + pointMark.foregroundStyle(pointMarkColor) } } .chartYAxis { @@ -387,18 +422,19 @@ struct LiveActivity: Widget { @ViewBuilder func content(context: ActivityViewContext) -> some View { let hasStaticColorScheme = context.state.glucoseColorScheme == "staticColor" + // TODO: grab target from proper targets, do not hard code. 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 + offset: 20 ) if let detailedViewState = context.state.detailedViewState { HStack(spacing: 12) { - chart(context: context, additionalState: detailedViewState, glucoseColor: glucoseColor) + chart(context: context, additionalState: detailedViewState) .frame(maxWidth: UIScreen.main.bounds.width / 1.8) VStack(alignment: .leading) { Spacer() @@ -465,14 +501,16 @@ struct LiveActivity: Widget { let glucoseValueForColor = context.state.bg let highGlucose = context.state.highGlucose let lowGlucose = context.state.lowGlucose + let hasStaticColorScheme = context.state.glucoseColorScheme == "staticColor" + // TODO: grab target from proper targets, do not hard code. let glucoseColor = getDynamicGlucoseColor( glucoseValue: Decimal(string: glucoseValueForColor) ?? 100, highGlucoseColorValue: highGlucose, lowGlucoseColorValue: lowGlucose, targetGlucose: 90, glucoseColorScheme: context.state.glucoseColorScheme, - offset: context.state.detailedViewState?.unit == "mg/dL" ? Decimal(20) : Decimal(20).asMmolL + offset: 20 ) print("Glucose color: \(glucoseColor)") @@ -494,7 +532,7 @@ struct LiveActivity: Widget { if context.state.isInitialState { expiredLabel() } else if let detailedViewState = context.state.detailedViewState { - chart(context: context, additionalState: detailedViewState, glucoseColor: glucoseColor) + chart(context: context, additionalState: detailedViewState) } else { Group { updatedLabel(context: context).font(.caption).foregroundStyle(Color.secondary) From 24a7f4c4e9aed31609fd6d456b9d0d337c0e5cf9 Mon Sep 17 00:00:00 2001 From: Deniz Cengiz Date: Sun, 29 Sep 2024 16:43:01 +0200 Subject: [PATCH 17/17] Remove print statements --- LiveActivity/LiveActivity.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/LiveActivity/LiveActivity.swift b/LiveActivity/LiveActivity.swift index 904d1e156..dc7475828 100644 --- a/LiveActivity/LiveActivity.swift +++ b/LiveActivity/LiveActivity.swift @@ -79,13 +79,6 @@ struct LiveActivity: Widget { let highGlucose = highGlucoseColorValue + (offset * 1.75) let targetGlucose = targetGlucose - print("glucoseValue: \(glucoseValue)") - print("lowGlucose: \(lowGlucose)") - print("highGlucose: \(highGlucose)") - print("targetGlucose: \(targetGlucose)") - print("glucoseColorScheme: \(glucoseColorScheme)") - print("offset: \(offset)") - // Only use calculateHueBasedGlucoseColor if the setting is enabled in preferences if glucoseColorScheme == "dynamicColor" { return calculateHueBasedGlucoseColor( @@ -513,8 +506,6 @@ struct LiveActivity: Widget { offset: 20 ) - print("Glucose color: \(glucoseColor)") - return DynamicIsland { DynamicIslandExpandedRegion(.leading) { bgAndTrend(