Skip to content

[Part 3 of 3] refactor: rework CGM settings screen and persist sensor state across launches - #44

Open
ETolboom wants to merge 15 commits into
LoopKit:mainfrom
ETolboom:feat/settings-view-rework
Open

[Part 3 of 3] refactor: rework CGM settings screen and persist sensor state across launches#44
ETolboom wants to merge 15 commits into
LoopKit:mainfrom
ETolboom:feat/settings-view-rework

Conversation

@ETolboom

@ETolboom ETolboom commented Aug 18, 2026

Copy link
Copy Markdown

Reworks the CGM settings screen's sensor status row into a richer status display (LibreSensorStatusDisplay, mirroring SyaiKit/LibreLoop's status display pattern) and persists sensor lifecycle state across app launches so status is meaningful before the first BLE read completes this session. Also adds an independent low-battery warning row for bridge transmitters (MiaoMiao/Bubble/Blucon), separate from the sensor lifecycle status since bridge battery is unrelated hardware state.

Since this was first opened, 5 more commits landed on top:

  • fix: LibreGlucose's initializer accepted a parsed MeasurementError array but never assigned it to self.error — every reading silently reported .OK regardless of what the sensor's raw error bitfield said. Also shows the live sensor type (e.g. "Libre 2") as the settings screen title instead of a generic "FreeStyle Libre".
  • feat: surfaces those now-correctly-propagated measurement error bits (temperature out of range, rate-of-change too fast, signal saturated, etc.) in the sensor status row as "Sensor Issues", instead of showing "Sensor OK" while the sensor is actively reporting a problem. Wording for the Abbott-documented cases is grounded in their own app's semantics; the rest are placeholders pending official terminology.
  • fix (behavior change, please review closely): removes the "Last Blood Sugar prediction" feature entirely — a 10-minute-ahead linear-regression extrapolation of raw glucose. It was already display-only (never delivered as an actual CGM sample), but keeping a speculative future value like this around in a codebase that can feed an automated dosing pipeline is a real risk, not just clutter. Removed the UI section and its full pipeline (both transmitter paths, the regression helper, the dead observable fields).
  • chore: backfills Localizable.xcstrings entries for strings from earlier commits in this stack that were never synced into the catalog. Mechanical, no new copy.
  • fix: the settings screen has no NavigationStack, so .navigationTitle never actually reached UIKit — the root screen, "Device details", and the calibrations screen all showed a blank nav bar title. Titles are now set directly on navigationItem, matching SyaiKit's pattern. Also fixes the calibration screen's warning banner, which was rendering as a sibling of its List instead of a row inside it and breaking the title layout.

Part 3 of 3 related PRs. Built on top of #43 in my fork, so this diff will include #42 and #43's changes until those merge and this gets rebased.

  1. [Part 1 of 3] refactor: add cgm lifecycle progress and support new alerting system #42 — refactor: add cgm lifecycle progress and support new alerting system
  2. [Part 2 of 3] fix: disable redundant glucose smoothing #43 — fix: disable redundant glucose smoothing
  3. This PR

Copilot AI lite review requested due to automatic review settings August 18, 2026 09:16
@ETolboom ETolboom changed the title refactor: rework CGM settings screen and persist sensor state across launches [Part 3 of 3] refactor: rework CGM settings screen and persist sensor state across launches Aug 18, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the CGM settings experience by introducing a richer, lifecycle-driven sensor status display, persisting key sensor state across launches via CGMManager.rawState, and moving lifecycle user-notifications onto LoopKit’s native Alert framework (while adding a separate bridge-transmitter low-battery warning row).

Changes:

  • Persist last-known sensor/session state across launches using LibreCGMManagerState and rawState/init(rawState:).
  • Add unified lifecycle + alerting surfaces (LibreSensorLifecycle, LibreAlertCondition, evaluateAlerts()), and wire them into LoopKit UI hooks (badge/highlight/progress).
  • Rework Settings UI sensor status row (LibreSensorStatusDisplay) and remove legacy notification/alarm/snooze/glucose-settings UI + NotificationHelper-based alerting.

Reviewed changes

Copilot reviewed 33 out of 34 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
readme.md Removes mention of now-deleted glucose smoothing behavior.
LibreTransmitterUI/Views/Setup/Libre2DirectSetup.swift Removes legacy NotificationHelper calibration/setup notifications.
LibreTransmitterUI/Views/Setup/BluetoothSelection.swift Removes notification permission request hook tied to removed notification system.
LibreTransmitterUI/Views/Settings/SnoozeView.swift Deletes legacy snooze UI.
LibreTransmitterUI/Views/Settings/SettingsView.swift Reworks settings layout and adds sensor status + bridge battery warning rows.
LibreTransmitterUI/Views/Settings/NotificationSettingsView.swift Deletes legacy notification settings UI.
LibreTransmitterUI/Views/Settings/LibreSensorLifecycle+Display.swift Adds new settings-row-friendly sensor status display model.
LibreTransmitterUI/Views/Settings/GlucoseSettingsView.swift Deletes legacy glucose settings UI.
LibreTransmitterUI/Views/Settings/AlarmSettings/CustomDataPickerView.swift Deletes legacy alarm schedule UI component.
LibreTransmitterUI/Views/Settings/AlarmSettings/CriticalAlarmsVolumeView.swift Deletes legacy critical-alarm volume UI.
LibreTransmitterUI/Views/Settings/AlarmSettings/AlarmSettingsView.swift Deletes legacy alarm settings UI.
LibreTransmitterUI/LibreTransmitterManager+UI.swift Implements LoopKit UI surfaces (badge/highlight/progress) based on lifecycle.
LibreTransmitter/Observables/TransmitterInfo.swift Adds batteryPercent observable for bridge battery warning and equality updates.
LibreTransmitter/Observables/SensorInfo.swift Adds published lifecycle + pairing state for UI consumption.
LibreTransmitter/Observables/AlarmStatus.swift Deletes legacy alarm-status observable used by removed UI.
LibreTransmitter/NotificationHelperOverride.swift Deletes legacy notification override toggle.
LibreTransmitter/NotificationHelper.swift Deletes legacy local notification + schedule-based alerting implementation.
LibreTransmitter/LibreTransmitterManagerV3.swift Persists/restores state, adds lifecycle computation, and integrates alert evaluation.
LibreTransmitter/LibreTransmitterManager+Transmitters.swift Removes notification side-effects; records fault/lifecycle info and triggers alert evaluation.
LibreTransmitter/LibreTransmitterManager+Libre2EU.swift Removes legacy expiry notifications; triggers alert evaluation post-observable updates.
LibreTransmitter/LibreGlucose.swift Removes redundant smoothing and uses calibrated glucose directly.
LibreTransmitter/LibreCGMManagerState.swift New persisted state container for rawState round-tripping.
LibreTransmitter/Alerting/LibreTransmitterManagerV3+Alerts.swift Adds lifecycle alert diffing and persistence update logic.
LibreTransmitter/Alerting/LibreSensorLifecycle.swift New unified lifecycle model across data paths.
LibreTransmitter/Alerting/LibreAlertCondition.swift Maps lifecycle states to LoopKit Alerts and identifiers.
LibreTransmitter/.gitignore Removes ignore rule for deleted notification override file.
LibreTransmitter.xcodeproj/project.pbxproj Updates project file references to add new files/remove deleted legacy UI/notification files.
LibreSensor/GlucoseAlgorithm/GlucoseSmoothing.swift Deletes the old smoothing implementation.
Features.swift Removes legacy flags tied to deleted alarm/vibration behavior.
Common/Settings/UserDefaults+Bluetooth.swift Adds dangerModeActivated key and shared optionalBool(forKey:).
Common/Settings/UserDefaults+Alarmsettings.swift Deletes legacy alarm/notification-related UserDefaults helpers.
Common/Settings/GlucoseSchedules.swift Deletes legacy glucose schedule model used by removed alarm notifications.
build.md Removes build instructions for removed critical-alerts/vibration features; simplifies build steps.
.gitignore Removes ignore rule for deleted notification override file.
Suppressed comments (1)

LibreTransmitter/Observables/TransmitterInfo.swift:25

  • TransmitterInfo conforms to Hashable and implements value-based ==, but (via the Hashable where Self: AnyObject extension) its hash is based on object identity. This violates Hashable’s requirement that equal values must hash the same, and can break Sets/Dictionaries if TransmitterInfo is ever used as a key.
    public static func == (lhs: TransmitterInfo, rhs: TransmitterInfo) -> Bool {
         lhs.battery == rhs.battery && lhs.batteryPercent == rhs.batteryPercent && lhs.hardware == rhs.hardware &&
         lhs.firmware == rhs.firmware && lhs.connectionState == rhs.connectionState &&
         lhs.transmitterType == rhs.transmitterType && lhs.transmitterMacAddress == rhs.transmitterMacAddress &&
         lhs.sensorType == rhs.sensorType

     }

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread LibreTransmitterUI/Views/Settings/SettingsView.swift
Comment thread LibreTransmitterUI/Views/Settings/LibreSensorLifecycle+Display.swift Outdated
Comment thread LibreTransmitterUI/LibreTransmitterManager+UI.swift
ETolboom and others added 2 commits August 18, 2026 11:31
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@ETolboom
ETolboom force-pushed the feat/settings-view-rework branch from d23c91b to bc04bf6 Compare August 18, 2026 10:34
Trio already applies its own smoothing to incoming glucose values, so
the 5-point boxcar moving-average filter (CalculateSmothedData5Points)
previously run on every trend reading here only added extra lag on top
of Trio's own smoothing, with no benefit. Remove the filter and the
now-dead GlucoseSmoothing.swift entirely.
…launches

- Reorganize the settings screen: add a sensor status row (icon + text)
  driven by the sensor lifecycle, separate sensor identity fields from
  device/transmitter fields into their own section, group maintenance
  actions under a "Manage" section, give the pushed "Device details"
  screen a title, and remove the now-redundant "Glucose Settings" screen.
- Fix the sensor status resolving to "No Sensor" instead of "Connecting"
  on a fresh launch: gate the status display on persisted pairing state
  first (independent of the lifecycle enum, which only resolves after a
  live read), and correct an ordering bug where the lifecycle was
  evaluated before setObservables() had updated the underlying sensor
  info it depends on.
- Implement CGMManager.rawState/init(rawState:) persistence (previously
  a no-op stub), matching what other LoopKit CGM drivers already do, so
  sensor identity/timing/status can be restored immediately at launch
  instead of waiting for the first live BLE read of each session.
…trings

Backfills catalog entries for strings introduced in earlier commits
(LibreAlertCondition, the bridge battery row, sensor lifecycle status
rows) that were never synced into the String Catalogs.
…itle

LibreGlucose's initializer accepted a MeasurementError array but never
assigned it to self.error, so every reading silently reported .OK
regardless of what the sensor's raw error bitfield actually said.
Also show the live sensor type (e.g. "Libre 2") as the settings
screen title instead of the generic "FreeStyle Libre".
Decode the raw per-reading firmware error/quality bits (temperature
out of range, rate-of-change too fast, signal saturated, etc.) that
were already being parsed but silently dropped, and surface them in
the sensor status row instead of showing "Sensor OK" when the sensor
is actively reporting a problem. Wording for TEMP_HIGH, TEMP_LOW,
THERMISTOR_OUT_OF_RANGE, PEAK_DELTA_EXCEEDED, AVG_DELTA_EXCEEDED,
SIGNAL_SATURATED, SENSOR_SIGNAL_LOW, and INVALID_DATA is grounded in
Abbott's own Android app data-processing semantics; the remaining
cases are best-effort placeholders pending official terminology.
The 10-minute-ahead linear regression extrapolation shown as "Last
Blood Sugar prediction" was display-only, but a speculative future
value like this is actively dangerous to keep around in a codebase
that feeds an automated insulin dosing system - it invites exactly
the kind of misuse (treating a guess as data) an OS-AID pipeline
can't afford. Removed the section and its entire pipeline: the
per-sensor prediction call sites, the linear regression helper, and
the now-dead GlucoseArrayWithPrediction/prediction observable fields.
SettingsView has no NavigationStack, so .navigationTitle never reached
UIKit. Titles for the root screen, device details, and calibrations
are now set directly on navigationItem, matching SyaiKit's pattern.
Also fixes the calibration warning banner sitting outside the List
and breaking title layout.
Left behind by the stack rebase: the sync commit on this branch
re-added the key independently of the fix (now living on
feat/cgm-lifecycle+alerts) that removed the code referencing it.
@ETolboom
ETolboom force-pushed the feat/settings-view-rework branch from 4821e84 to 245619c Compare August 19, 2026 08:26
@dabear

dabear commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

rebase on next-dev and submit please. Preferably Add "persist sensor state" to its own PR if possible, to keep the amount of changes low enough to test individually in-vivo

@ETolboom

Copy link
Copy Markdown
Author

Hi dabear,

I'll take a look at rebasing against dev-next for this PR as well.

Also I forgot to add screenshots from my own in-vivo testing:

CGM Lifecycle (PR42) Settings Reworked 1 Settings Reworked 2
image image image image

The sensor status row, currently displaying "Sensor OK" would display "Temperature too high" etc. when applicable.

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.

3 participants