From a65d1d94c65791f84478036a9bfa1bc45875b825 Mon Sep 17 00:00:00 2001 From: ETolboom Date: Sun, 4 Oct 2026 01:05:58 +0200 Subject: [PATCH] feat(battery): warn about a very low transmitter battery in settings and on the host's home screen A tester ran on a transmitter at 2.54 V for a day: dropped connections, late readings and an End Sensor that never got through, with nothing on screen explaining why. - Settings: while battery B is very low (2.70 V or below, the existing threshold), the Sensor section ends with a red-tinted row explaining that readings may be missing and the transmitter may not respond, including to stopping a session or calibrating. - Home screen: cgmStatusHighlight reports "Transmitter Low" (warning), ranked below sensor failed / warm-up / expired / no sensor and above calibration needed and signal loss, since the battery is the likely cause of both. - cgmLifecycleProgress reports a warning state while the battery is very low. Trio only shows the plugin's status highlight while progress is not normal, so without this the highlight stays hidden for most of a session. --- G6SensorKitUI/G6CGMManager+UI.swift | 18 ++++++++++++++- G6SensorKitUI/Localizable.xcstrings | 12 ++++++++++ G6SensorKitUI/Views/G6SettingsView.swift | 29 ++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/G6SensorKitUI/G6CGMManager+UI.swift b/G6SensorKitUI/G6CGMManager+UI.swift index 6e9f27d..84b5ef0 100644 --- a/G6SensorKitUI/G6CGMManager+UI.swift +++ b/G6SensorKitUI/G6CGMManager+UI.swift @@ -117,6 +117,18 @@ extension G6CGMManager: CGMManagerUI { ) } + // Ahead of calibration and signal loss: a dying battery is the likely + // cause of both, and replacing the transmitter is the actual fix. The + // highlight is the host's home-screen tag, so this is the one place + // the user sees it without opening settings. + if state.isBatteryVeryLow { + return G6StatusHighlight( + localizedMessage: LocalizedString("Transmitter Low", comment: "Status highlight when the transmitter battery is very low"), + imageName: "battery.0percent", + state: .warning + ) + } + if let reading = state.latestReading, reading.calibrationState.needsCalibration { return G6StatusHighlight( localizedMessage: LocalizedString("Calibration Needed", comment: "Status highlight when a calibration is requested"), @@ -162,7 +174,11 @@ extension G6CGMManager: CGMManagerUI { let progressState: DeviceLifecycleProgressState if remaining <= 0 { progressState = .critical - } else if remaining <= .hours(24) { + } else if remaining <= .hours(24) || state.isBatteryVeryLow { + // A dying transmitter battery counts too. Trio shows the status + // highlight ("Transmitter Low") on its home screen only while + // the progress is not normal, so without this it would stay + // hidden for most of a session. progressState = .warning } else { progressState = .normalCGM diff --git a/G6SensorKitUI/Localizable.xcstrings b/G6SensorKitUI/Localizable.xcstrings index f218d5c..d941549 100644 --- a/G6SensorKitUI/Localizable.xcstrings +++ b/G6SensorKitUI/Localizable.xcstrings @@ -1,6 +1,10 @@ { "sourceLanguage": "en", "strings": { + "Readings may be missing or arrive late, and the transmitter may respond slowly or not at all — including to stopping a session or calibrating. Replace the transmitter as soon as you can, and check your glucose with a fingerstick meter if readings stop.": { + "comment": "Settings banner body when the transmitter battery is very low", + "extractionState": "manual" + }, "Sensor Failed": { "extractionState": "manual", "comment": "Status highlight for failed sensor" @@ -49,6 +53,14 @@ "extractionState": "manual", "comment": "Navigation title for pairing screen" }, + "Transmitter Low": { + "comment": "Status highlight when the transmitter battery is very low", + "extractionState": "manual" + }, + "Transmitter battery very low": { + "comment": "Settings banner title when the transmitter battery is very low", + "extractionState": "manual" + }, "Warm-Up": { "extractionState": "manual", "comment": "Navigation title for warm-up screen" diff --git a/G6SensorKitUI/Views/G6SettingsView.swift b/G6SensorKitUI/Views/G6SettingsView.swift index 1cc7742..17f12c6 100644 --- a/G6SensorKitUI/Views/G6SettingsView.swift +++ b/G6SensorKitUI/Views/G6SettingsView.swift @@ -292,11 +292,40 @@ struct G6SettingsView: View { .foregroundStyle(.orange) } } + + // Last, so the session's own status reads first and the battery + // explains it underneath. + if viewModel.state.isBatteryVeryLow { + batteryVeryLowRow + } } header: { Text(LocalizedString("Sensor", comment: "Settings section: sensor")) } } + /// The Sensor section's last row. Stays up for as long as the battery + /// reads very low; there is nothing to dismiss, because the only fix is + /// a new transmitter. A tester ran on a near-dead battery for a day of + /// dropped connections and an End Sensor that never got through, with + /// nothing on this screen to explain why. + private var batteryVeryLowRow: some View { + HStack(alignment: .top, spacing: 12) { + Image(systemName: "battery.0percent") + .font(.title2) + .foregroundStyle(.red) + VStack(alignment: .leading, spacing: 4) { + Text(LocalizedString("Transmitter battery very low", comment: "Settings banner title when the transmitter battery is very low")) + .font(.subheadline.weight(.semibold)) + Text(LocalizedString("Readings may be missing or arrive late, and the transmitter may respond slowly or not at all — including to stopping a session or calibrating. Replace the transmitter as soon as you can, and check your glucose with a fingerstick meter if readings stop.", comment: "Settings banner body when the transmitter battery is very low")) + .font(.footnote) + .foregroundStyle(.secondary) + .fixedSize(horizontal: false, vertical: true) + } + } + .padding(.vertical, 4) + .listRowBackground(Color.red.opacity(0.12)) + } + private var lastReadingSection: some View { Section(LocalizedString("Last Reading", comment: "Settings section: last reading")) { if let reading = viewModel.state.latestReading, !viewModel.state.isInWarmup {