Skip to content

[1/6] Add a Trends screen for glucose, insulin and Loop status - #2637

Open
Nutcasey wants to merge 2 commits into
LoopKit:next-devfrom
Nutcasey:redesign-1-trends
Open

Nutcasey wants to merge 2 commits into
LoopKit:next-devfrom
Nutcasey:redesign-1-trends

Conversation

@Nutcasey

@Nutcasey Nutcasey commented Nov 1, 2026 •

Copy link
Copy Markdown

Part 1 of 6 splitting #2621. Review commits 91a5ba00 (Trends) and e6136415 (what came across from Statistics).

Trends is a review of one period at a time: a day, 7, 14, 30 or 90 days.

  • Summary tiles: average glucose with SD and CV, GMI, insulin, carbs and boluses per day, and how long Loop was closed loop.
  • Cards: time in range, the daily pattern (AGP), basal and bolus, insulin per day, and Loop status with a list of its gaps.
  • One day: a one-day period leads with that day's timeline.
  • Drill-down: tapping a day opens a day page with the insulin timeline and active insulin and carbs, stepping a day at a time.
  • Export: a PDF report, or a CSV with one row per day.

Inside Loop's 7 days the figures come from Loop's own stores, so manual and automatic boluses, temp basals, historical targets and presets are known. Older days come from Apple Health. Closed and open loop are recorded from launch, because LoopDataManager.automationHistory keeps only 36 hours.

Where it opens. Before the home screen changes, Trends opens from Settings → Trends, beside Statistics, as a sheet with its own navigation and a Done button. Statistics and Current Setup are unchanged. A pushed screen didn't work here: navigationDestination does nothing inside Settings' NavigationView, so the day page and Gaps wouldn't open.

Trends, 14 days Trends, daily pattern and insulin Trends, insulin and Loop status Day page

Screenshots are from #2621, where Trends is a tab. Here the same screen opens from Settings with a Done button.

What came across from Statistics

Trends and Statistics answer the same question, so the second commit (e6136415) brings into Trends everything Statistics shows that Trends lacked. Trends already had the 7/14/30/90-day ranges, GMI, average, CV, CGM active, time in range, the daily pattern and daily insulin with its basal, bolus and automatic split.

On Statistics Now on Trends
"Goal:" under GMI (<7%), Average (<154 mg/dL), Variability (≤36%) and CGM Active (>70%) One "Aim:" line under the summary tiles: average under 8.6 mmol/L (154 mg/dL), GMI under 7%, CV 36% or less. CGM active over 70% is on the Time in range card, beside its figure.
Time in range goals: in range >70%, above <25%, below <4%, very high <5%, very low <1% The Time in range card's "Aim:" line carries all five.
"Usually X U by HH:MM" under Today Under "Total so far" on today's Day view, and under the Insulin per day chart on longer periods ending today. Same InsulinDeliveryHistory.typicalDelivery, so the same figure.
"· scheduled X U" beside average basal "Scheduled X U" under Basal in Basal and bolus: the schedule that applied (stored profile with presets), or today's schedule where the profile history doesn't reach.
"Showing N days of data…" when the period isn't full "CGM data covers N of M days." under Summary.
Fingerstick (user-entered) readings left out of the figures Left out of every Trends figure too. The day timeline still draws them.

Not carried over: "This device keeps N days of glucose. Increase the cache duration…" (Trends reads older days from Apple Health, so the local cache doesn't limit it), and the two helper lines "Each 5% increase in range is clinically beneficial" and "Each 1% time in range ≈ 15 minutes" (Trends shows each band's hours a day).

On the same 14 days of simulator data, GMI, average, CV, CGM active, "usually by now" and scheduled basal match Statistics exactly. Statistics is still in Settings in this part so the two can be compared side by side. Once you're happy Trends covers it, removing Statistics is a small follow-up.

The additions on Trends, outlined

Differences from #2621

  • Ported to Use LoopKit's value types and bridge to LoopAlgorithm #2635's split between LoopKit and LoopAlgorithm types. The IOB and COB timelines for the day page convert with algorithmSchedule() and .loopKit, as LoopDataManager does.
  • Trends and the day page's timeline card (DayTimelineCard, DayTotalsTiles) live in DayDetailView.swift, not NowScreen.swift, because Trends needs them before Now exists.
  • TrendsView takes an optional done closure for the Settings sheet.
  • The Loop status footnotes say closed and open loop are recorded "from when this version of Loop first ran" rather than "from when the new interface was first opened". Recording starts at launch whatever the interface. The two strings have new translations.
  • Review fixes: the provider caches the start of Loop's dose records only once it has found one. Before, a day viewed before any records could cache "none" for five minutes, and later days then lost the programmed-rate basal fill. Also removes the unused RangeBand.name/thresholds and Summary.loopCoverageStart.

Testing

On the loop simulator (iOS 27.0, Pump and CGM Simulators, 90 days of history), driven through XCUITest:

  • Settings → Trends sheet → Day → today's card → day page → previous day → back.
  • 14 days → Gaps → back. Export → CSV and PDF share sheets. 90 days. Done returns to Settings.
  • Swiping the sheet down also returns to Settings.
  • The Statistics additions: 14 days, today's and yesterday's Day view, and a 90-day period where readings start late. GMI, average, CV, CGM active, usual-by-now and scheduled basal checked against Statistics on the same data.

LoopTests (448 run on this part, on next-dev 5ee95cc6): all pass except BolusEntryViewModelTests.testCarbEntryDateAndAbsorptionTimeString and …String2, which fail the same way on plain next-dev ("12:00 PM" against "12:00"). Xcode's hosted test run stalls at test-host launch on this machine, so these ran in the app bundle under Xcode's simulator XCTest agent, with next-dev's test classes except the HealthKit-hosted DeviceDataManagerTests. Every part was built on its own, in order, on the loop simulator.

The series

#2621 is split into six PRs, in the order Pete suggested: statistics and Trends first, then the Logbook, then the home screen. Add carbs, the widget and Live Activity, and the appearance options follow as their own parts. Each part builds on the one before it and targets next-dev (5ee95cc6, after #2635), so a PR shows the earlier parts' commits too. Review only the last commit of each PR (part 1 has two: Trends, then what came across from Statistics). #2621 stays open as the combined reference until the series lands.

  1. [1/6] Add a Trends screen for glucose, insulin and Loop status #2637 Trends, opened from Settings
  2. [2/6] Add a Logbook of the last 7 days #2638 Logbook, opened from Settings
  3. [3/6] Add the Now home screen with Now, Trends, Logbook and Settings tabs #2639 Now home screen with Now, Trends, Logbook and Settings tabs, and the New Interface toggle
  4. [4/6] Rebuild Add carbs around a live preview of the meal #2640 Redesigned Add carbs
  5. [5/6] Restyle the widget, Dynamic Island and Live Activity for the new interface #2641 Widget, Dynamic Island and Live Activity
  6. [6/6] Add Day and Night app icons and an appearance setting #2642 Day and Night app icons and the appearance setting

The six parts together match #2621 apart from the changes listed under "Differences from #2621" in each part.

Merging. Merged in order with merge commits, all six apply cleanly. With squash merges, each next PR needs a rebase onto next-dev once the previous one lands, because it still carries the earlier part's original commit. I've checked that every one of those rebases applies cleanly and that the end result is identical to part 6. I'll rebase each PR as the one before it merges.

Strings. Each part adds only its own catalogue entries, with their translations in Loop's languages, and fills in translations for the existing keys it starts using. GitHub's line diff of Localizable.xcstrings can show deletions where Xcode's ordering interleaves new keys. Parsed as JSON, no part removes or rewrites any existing entry.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QHnVP7ynB62LNuuYMy3yvH

Trends reviews one period at a time (a day, 7, 14, 30 or 90 days) on
one screen: summary tiles (average with SD and CV, GMI, insulin, carbs
and boluses per day, Loop active), time in range, the daily pattern
(AGP), basal and bolus, insulin per day and Loop status with its gaps.
A one-day period leads with that day's timeline. Tapping a day opens
a day page with the insulin timeline and active insulin and carbs,
stepping a day at a time. The period exports as a PDF report or a CSV
with one row per day.

Inside Loop's 7 days the figures come from Loop's own stores, so manual
and automatic boluses, temp basals, historical targets and presets are
known. Older days come from Apple Health. Closed and open loop are
recorded from launch, because Loop's automation history only covers
36 hours.

Trends opens from Settings, beside Statistics, as a sheet with its own
navigation and a Done button. Statistics and Current Setup are
unchanged.

This is part 1 of 6 splitting LoopKit#2621.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHnVP7ynB62LNuuYMy3yvH
Trends now carries everything Statistics shows that it lacked, so it
can take Statistics' place:

- Consensus goals: average under 8.6 mmol/L (154 mg/dL), GMI under 7%
  and CV 36% or less under the summary tiles; time in range over 70%,
  under 25% above and 4% below, under 5% very high and 1% very low,
  and CGM active over 70% on the Time in range card.
- Scheduled basal under Basal in Basal and bolus: the schedule that
  applied over the same days (the stored profile with presets), or
  today's schedule where the profile history doesn't reach.
- "Usually X U by HH:MM": today's insulin against the median by this
  time over the last 14 days, from InsulinDeliveryHistory as on
  Statistics. Under Total so far on today's Day view, and under the
  Insulin per day chart on longer periods ending today.
- "CGM data covers 5 of 14 days." under Summary when readings start
  partway through the period.
- Typed-in (fingerstick) readings are left out of every figure, as on
  Statistics. The day timeline still draws them.

Each new line reuses a pattern already on the screen: the Aim
footnote, the indented line under Bolus, and the muted footnote.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QHnVP7ynB62LNuuYMy3yvH
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant