From 41d871575f8b27468921b33bf03fdf33d37d45ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Sun, 27 Sep 2026 13:35:15 +0200 Subject: [PATCH] Use the selected range mode for Live Activity colors The Live Activity now colors the reading against the same low and high values as the chart and BG header, so TIR and TITR use 70-180 and 70-140 and Custom uses the user's lines. A reading exactly on a line counts as low or high, like in the header. Changing the range mode refreshes the Live Activity. --- .../LiveActivity/LiveActivityManager.swift | 24 +++++++++---------- .../ViewControllers/MainViewController.swift | 1 + .../LoopFollowLiveActivity.swift | 12 +++++----- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/LoopFollow/LiveActivity/LiveActivityManager.swift b/LoopFollow/LiveActivity/LiveActivityManager.swift index 125ba4e09..e8eb43de3 100644 --- a/LoopFollow/LiveActivity/LiveActivityManager.swift +++ b/LoopFollow/LiveActivity/LiveActivityManager.swift @@ -182,10 +182,7 @@ final class LiveActivityManager { let provider = StorageCurrentGlucoseStateProvider() guard let snapshot = GlucoseSnapshotBuilder.build(from: provider) else { return } - LAAppGroupSettings.setThresholds( - lowMgdl: Storage.shared.lowLine.value, - highMgdl: Storage.shared.highLine.value, - ) + writeThresholds() GlucoseSnapshotStore.shared.save(snapshot) seq += 1 @@ -624,10 +621,7 @@ final class LiveActivityManager { let provider = StorageCurrentGlucoseStateProvider() if let snapshot = GlucoseSnapshotBuilder.build(from: provider) { - LAAppGroupSettings.setThresholds( - lowMgdl: Storage.shared.lowLine.value, - highMgdl: Storage.shared.highLine.value, - ) + writeThresholds() LAAppGroupSettings.setDisplayName( Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String ?? "LoopFollow", show: Storage.shared.showDisplayName.value @@ -904,6 +898,12 @@ final class LiveActivityManager { } } + /// Publishes the range for the selected time-in-range mode, matching the chart and BG header. + private func writeThresholds() { + let thresholds = UnitSettingsStore.shared.effectiveThresholds() + LAAppGroupSettings.setThresholds(lowMgdl: thresholds.low, highMgdl: thresholds.high) + } + private func performRefresh(reason: String) { let provider = StorageCurrentGlucoseStateProvider() guard let snapshot = GlucoseSnapshotBuilder.build(from: provider) else { @@ -928,12 +928,10 @@ final class LiveActivityManager { let forceRefreshNeeded = timeSinceLastUpdate >= 5 * 60 // Capture dedup result BEFORE saving so the store comparison is valid. let snapshotUnchanged = GlucoseSnapshotStore.shared.load() == snapshot + let thresholdsChanged = LAAppGroupSettings.thresholdsMgdl() != UnitSettingsStore.shared.effectiveThresholds() // Store + Watch: always update, independent of LA state. - LAAppGroupSettings.setThresholds( - lowMgdl: Storage.shared.lowLine.value, - highMgdl: Storage.shared.highLine.value, - ) + writeThresholds() GlucoseSnapshotStore.shared.save(snapshot) // WatchConnectivityManager.shared.send(snapshot: snapshot) @@ -946,7 +944,7 @@ final class LiveActivityManager { LogManager.shared.log(category: .general, message: "[LA] refresh: LA update skipped — dismissedByUser=true reason=\(reason)") return } - guard !snapshotUnchanged || forceRefreshNeeded else { return } + guard !snapshotUnchanged || thresholdsChanged || forceRefreshNeeded else { return } guard ActivityAuthorizationInfo().areActivitiesEnabled else { LogManager.shared.log(category: .general, message: "[LA] refresh: LA update skipped — areActivitiesEnabled=false reason=\(reason)") return diff --git a/LoopFollow/ViewControllers/MainViewController.swift b/LoopFollow/ViewControllers/MainViewController.swift index 06c5e1f76..05d96f309 100644 --- a/LoopFollow/ViewControllers/MainViewController.swift +++ b/LoopFollow/ViewControllers/MainViewController.swift @@ -282,6 +282,7 @@ class MainViewController: UIViewController, UNUserNotificationCenterDelegate { .sink { [weak self] _ in self?.updateBGGraphSettings() self?.updateBGGraph() + LiveActivityManager.shared.refreshFromCurrentState(reason: "range mode changed") } .store(in: &cancellables) diff --git a/LoopFollowLAExtension/LoopFollowLiveActivity.swift b/LoopFollowLAExtension/LoopFollowLiveActivity.swift index 6d438531e..177529a92 100644 --- a/LoopFollowLAExtension/LoopFollowLiveActivity.swift +++ b/LoopFollowLAExtension/LoopFollowLiveActivity.swift @@ -779,12 +779,12 @@ private enum LAColors { let low = t.low let high = t.high - if mgdl < low { - let raw = 0.48 + (0.85 - 0.48) * ((low - mgdl) / (low - 54.0)) + if mgdl <= low { + let raw = 0.48 + (0.85 - 0.48) * ((low - mgdl) / max(low - 54.0, 1)) let opacity = min(max(raw, 0.48), 0.85) return Color(uiColor: UIColor.systemRed).opacity(opacity) - } else if mgdl > high { - let raw = 0.44 + (0.85 - 0.44) * ((mgdl - high) / (324.0 - high)) + } else if mgdl >= high { + let raw = 0.44 + (0.85 - 0.44) * ((mgdl - high) / max(324.0 - high, 1)) let opacity = min(max(raw, 0.44), 0.85) return Color(uiColor: UIColor.systemOrange).opacity(opacity) } else { @@ -798,9 +798,9 @@ private enum LAColors { let low = t.low let high = t.high - if mgdl < low { + if mgdl <= low { return Color(uiColor: UIColor.systemRed) - } else if mgdl > high { + } else if mgdl >= high { return Color(uiColor: UIColor.systemOrange) } else { return Color(uiColor: UIColor.systemGreen)