Repository navigation
Conversation
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.
- Push an immediate Live Activity update when the custom low/high lines change. TIR/TITR use fixed ranges, so this only applies in custom mode. Thresholds are published through writeThresholds() so the effective range is always used. - Refresh the main stats pie when the range lines or range mode change. - Compare reading colors at mmol/L display precision, so two readings that both display as "3.9" get the same color. Applies to the chart, BG text, contact image and the Live Activity widget. mg/dL is unchanged. - Share the rounding via GlucoseConversion.toDisplayedMmol.
MtlPhil
marked this pull request as ready for review
October 12, 2026 16:37
MtlPhil
requested review from
bjorkert,
codebymini and
marionbarker
as code owners
October 12, 2026 16:37
MtlPhil
marked this pull request as draft
October 12, 2026 17:46
…ndary - Route custom low/high line changes through refreshFromCurrentState instead of a separate hand-built Live Activity push, so the dismissed, enabled and in-flight checks apply and picker bursts are debounced. - Use effectiveThresholds() for the contact image so TIR and TITR modes match the chart, BG text and Live Activity. - Add GlucoseBand.of(_:low:high:mmol:) in Shared and use it for the chart, BG text, contact image, stats pie and the Live Activity widget. A reading on a line is low or high, compared at display precision. - Make the stats pie follow the same boundary rule. - Rename normalizeForColorComparison to normalizeToDisplayPrecision and shorten its comment.
- High, Low, activation limits and missed bolus alarms now round the reading and the threshold to the display precision of the current unit, so an alarm agrees with the number shown in mmol/L. - BGPicker converts mmol/L to mg/dL with GlucoseConversion.mmolToMgDl instead of a hardcoded 18. Existing saved values need no migration because both sides are rounded before comparing. - Add tests for boundary readings with both conversion factors.
Replace the function-reference/closure ternary with plain per-value conversions so the compiler can type-check it.
A reading exactly on the low or high line is now in range, matching the international consensus on time in range (70-180 mg/dL, 3.9-10.0 mmol/L). GlucoseBand, and so the chart, BG text, contact image, stats pie and Live Activity widget, use the inclusive rule at display precision. The TIR screen and GRI keep their inclusive bands and published cutoffs but now compare at display precision, so readings that display the same mmol/L value share a band. Alarm thresholds are unchanged.
MtlPhil
marked this pull request as ready for review
October 12, 2026 18:49
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
The app decided "low / in range / high" in several places, each with its own comparison. With custom range lines and mmol/L they could disagree with each other and with the number on screen: two readings that both display "3.9" could get different colors, and the Live Activity and stats pie could be stale after a range change.
Changes
GlucoseBand.of(_:low:high:mmol:)inShared/classifies a reading at the precision shown to the user. A reading on a line is in range. The chart, BG text, contact image, stats pie and Live Activity widget all use it (throughUnitSettingsStore.glucoseBand(for:thresholds:)in the app), replacing the repeated compare-and-pick-a-color blocks.GlucoseConversion.toDisplayedMmol), so readings that display the same value always get the same band. mg/dL is compared exactly as before.refreshFromCurrentState, the same path as a range-mode change, so the dismissed/enabled checks apply and a burst of picker changes collapses into one update (it lands after the existing 20 s refresh delay). Thresholds are published throughwriteThresholds()so the effective range is always used.effectiveThresholds(), so TIR and TITR modes match the chart, BG text and Live Activity.Adjacent changes (separate commit)
I have read the single-concern guideline in the README. I judged the two changes below adjacent to this fix rather than unrelated, because they apply the same display-precision rule to the places that would otherwise still disagree with the new colors. They are in their own commit (
Compare alarm thresholds at display precision and unify picker factor) so they can be split into a separate PR if you prefer.HighBGCondition,LowBGCondition, the activation limits inAlarmCondition.passesBGLimits, andMissedBolusConditionround the reading and the threshold the same way. Before, a custom 7.8 mmol/L high alarm was stored as 140.4 mg/dL, so a reading of 140 (displayed 7.8) did not trigger it even though the alarm is set at 7.8. The alarm boundary itself is unchanged (a High alarm still fires at its threshold, a Low alarm at or below it): an alarm threshold is a trigger, not a range. In mg/dL nothing changes; in mmol/L an alarm can fire one reading earlier or later at the boundary.BGPickerconversion factor. It converted mmol/L to mg/dL with a hardcoded18; it now usesGlucoseConversion.mmolToMgDl(18.01559), the same factor as the display. Values already saved with ×18 need no migration, because both sides are rounded before comparing.