Repository navigation
Devices: show the #592 battery-probe result in a copyable dialog - #601
Merged
Merged
Conversation
ryanbr
force-pushed
the
feat/battery-probe-result-dialog-592
branch
from
July 19, 2026 03:20
fdd7744 to
3a34fcd
Compare
Follow-up to #599. The probe wrote its result only to the strap log, so reading or sharing a capture meant a full log export. Surface it directly instead. - WhoopBleClient: publish the probe result (raw hex + payload triage + 5/MG result code) to a new `extendedBatteryProbe` StateFlow as well as the log; a "__waiting__" sentinel is set on send. If NO response arrives within EXTENDED_BATTERY_PROBE_TIMEOUT_MS (8s), the silence is surfaced + logged as a result in its own right — no-reply is evidence against opcode 98, and a stuck "waiting" dialog is avoided. clearExtendedBatteryProbe() resets it. - AppViewModel: expose the flow + clear. - DevicesScreen: when a result (or the waiting/no-reply state) arrives, a read-only dialog shows the text (monospace, selectable, scrollable) with a Copy button (LocalClipboardManager) so the capture pastes straight into #592 without exporting the whole log. - strings.xml (+de/es/fr): dialog title, waiting line, Copy, Close. The log lines are unchanged, so the strap-log bundle still carries the capture. Verified: full Android module compiles; testFullDebugUnitTest green; i18n audit --ci exit 0. Swift twin to follow with the probe twin.
ryanbr
force-pushed
the
feat/battery-probe-result-dialog-592
branch
from
July 19, 2026 03:22
3a34fcd to
f7d2a94
Compare
This was referenced Jul 19, 2026
ryanbr
added a commit
that referenced
this pull request
Jul 19, 2026
Parity fix for the Android side (#603/#601 extracted these to strings.xml). The 8 new DevicesView UI strings — the probe menu item, confirm dialog title + message, Send/waiting/result-title, and the voltage readout + a11y label — were plain literals (English-only, and a i18n-gate failure). Extract them to Localizable.xcstrings with de/es/fr; the voltage uses SwiftUI specifier interpolation so the number localizes too. i18n audit --ci exit 0.
ryanbr
added a commit
that referenced
this pull request
Jul 19, 2026
* iOS/macOS twin of the #592 extended-battery probe + voltage (#592) Swift port of the Android probe tooling (#599/#601/#603/#604): the read-only GET_EXTENDED_BATTERY_INFO(98) probe, its copyable result dialog, the strap voltage on the Devices card, and the field-mapping capture diff. - WhoopProtocol: ExtendedBatteryProbe.format(...) — the pure formatter (verdict, full raw hex, offset-labelled payload grid, decoded voltage, per-byte capture diff). Placed in the package (not app-side like Kotlin) so swift test covers it on Linux/CI; behaviour is byte-identical to the Kotlin formatter. 5 tests pin it against the real 4.0 capture, the diff, a bare stub, and a 5/MG UNSUPPORTED verdict. - BLEManager: probeExtendedBatteryInfo() (+ 8s no-reply timeout, guard-then-set is race-free since BLE callbacks + the timer both run on main), clearExtended..., the frame[6] (4.0) and frame[10] (5/MG) COMMAND_RESPONSE dumps, the 5/MG allowlist entry for 98, prev-payload persisted in UserDefaults (noop.592.prevPayload). - LiveState: batteryMv + extendedBatteryProbe (+ disconnect resets). - FrameRouter: consume battery_mV → state.batteryMv (event + command response). - AppModel: probeExtendedBatteryInfo()/clearExtendedBatteryProbe() forwards. - DevicesView: the probe menu item, a read-only confirm dialog, a copyable result sheet (selectable text + PlatformPasteboard Copy), and the voltage readout beside the battery percent. Design tokens only. Verified on Linux: WhoopProtocol builds + all 294 tests pass (incl. the 5 new); swiftc -parse clean on every app-target file. App-target compile (BLEManager / DevicesView / etc.) needs an app-build run — flagged. * iOS #592 probe: localize the Devices probe/voltage strings (de/es/fr) Parity fix for the Android side (#603/#601 extracted these to strings.xml). The 8 new DevicesView UI strings — the probe menu item, confirm dialog title + message, Send/waiting/result-title, and the voltage readout + a11y label — were plain literals (English-only, and a i18n-gate failure). Extract them to Localizable.xcstrings with de/es/fr; the voltage uses SwiftUI specifier interpolation so the number localizes too. i18n audit --ci exit 0.
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
ryanbr#601) Follow-up to ryanbr#599. The probe wrote its result only to the strap log, so reading or sharing a capture meant a full log export. Surface it directly instead. - WhoopBleClient: publish the probe result (raw hex + payload triage + 5/MG result code) to a new `extendedBatteryProbe` StateFlow as well as the log; a "__waiting__" sentinel is set on send. If NO response arrives within EXTENDED_BATTERY_PROBE_TIMEOUT_MS (8s), the silence is surfaced + logged as a result in its own right — no-reply is evidence against opcode 98, and a stuck "waiting" dialog is avoided. clearExtendedBatteryProbe() resets it. - AppViewModel: expose the flow + clear. - DevicesScreen: when a result (or the waiting/no-reply state) arrives, a read-only dialog shows the text (monospace, selectable, scrollable) with a Copy button (LocalClipboardManager) so the capture pastes straight into ryanbr#592 without exporting the whole log. - strings.xml (+de/es/fr): dialog title, waiting line, Copy, Close. The log lines are unchanged, so the strap-log bundle still carries the capture. Verified: full Android module compiles; testFullDebugUnitTest green; i18n audit --ci exit 0. Swift twin to follow with the probe twin.
DX23876
pushed a commit
to DX23876/noop
that referenced
this pull request
Jul 22, 2026
…anbr#605) * iOS/macOS twin of the ryanbr#592 extended-battery probe + voltage (ryanbr#592) Swift port of the Android probe tooling (ryanbr#599/ryanbr#601/ryanbr#603/ryanbr#604): the read-only GET_EXTENDED_BATTERY_INFO(98) probe, its copyable result dialog, the strap voltage on the Devices card, and the field-mapping capture diff. - WhoopProtocol: ExtendedBatteryProbe.format(...) — the pure formatter (verdict, full raw hex, offset-labelled payload grid, decoded voltage, per-byte capture diff). Placed in the package (not app-side like Kotlin) so swift test covers it on Linux/CI; behaviour is byte-identical to the Kotlin formatter. 5 tests pin it against the real 4.0 capture, the diff, a bare stub, and a 5/MG UNSUPPORTED verdict. - BLEManager: probeExtendedBatteryInfo() (+ 8s no-reply timeout, guard-then-set is race-free since BLE callbacks + the timer both run on main), clearExtended..., the frame[6] (4.0) and frame[10] (5/MG) COMMAND_RESPONSE dumps, the 5/MG allowlist entry for 98, prev-payload persisted in UserDefaults (noop.592.prevPayload). - LiveState: batteryMv + extendedBatteryProbe (+ disconnect resets). - FrameRouter: consume battery_mV → state.batteryMv (event + command response). - AppModel: probeExtendedBatteryInfo()/clearExtendedBatteryProbe() forwards. - DevicesView: the probe menu item, a read-only confirm dialog, a copyable result sheet (selectable text + PlatformPasteboard Copy), and the voltage readout beside the battery percent. Design tokens only. Verified on Linux: WhoopProtocol builds + all 294 tests pass (incl. the 5 new); swiftc -parse clean on every app-target file. App-target compile (BLEManager / DevicesView / etc.) needs an app-build run — flagged. * iOS ryanbr#592 probe: localize the Devices probe/voltage strings (de/es/fr) Parity fix for the Android side (ryanbr#603/ryanbr#601 extracted these to strings.xml). The 8 new DevicesView UI strings — the probe menu item, confirm dialog title + message, Send/waiting/result-title, and the voltage readout + a11y label — were plain literals (English-only, and a i18n-gate failure). Extract them to Localizable.xcstrings with de/es/fr; the voltage uses SwiftUI specifier interpolation so the number localizes too. i18n audit --ci exit 0.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
ryanbr#601) Follow-up to ryanbr#599. The probe wrote its result only to the strap log, so reading or sharing a capture meant a full log export. Surface it directly instead. - WhoopBleClient: publish the probe result (raw hex + payload triage + 5/MG result code) to a new `extendedBatteryProbe` StateFlow as well as the log; a "__waiting__" sentinel is set on send. If NO response arrives within EXTENDED_BATTERY_PROBE_TIMEOUT_MS (8s), the silence is surfaced + logged as a result in its own right — no-reply is evidence against opcode 98, and a stuck "waiting" dialog is avoided. clearExtendedBatteryProbe() resets it. - AppViewModel: expose the flow + clear. - DevicesScreen: when a result (or the waiting/no-reply state) arrives, a read-only dialog shows the text (monospace, selectable, scrollable) with a Copy button (LocalClipboardManager) so the capture pastes straight into ryanbr#592 without exporting the whole log. - strings.xml (+de/es/fr): dialog title, waiting line, Copy, Close. The log lines are unchanged, so the strap-log bundle still carries the capture. Verified: full Android module compiles; testFullDebugUnitTest green; i18n audit --ci exit 0. Swift twin to follow with the probe twin.
simoncad7
pushed a commit
to simoncad7/noop
that referenced
this pull request
Aug 17, 2026
…anbr#605) * iOS/macOS twin of the ryanbr#592 extended-battery probe + voltage (ryanbr#592) Swift port of the Android probe tooling (ryanbr#599/ryanbr#601/ryanbr#603/ryanbr#604): the read-only GET_EXTENDED_BATTERY_INFO(98) probe, its copyable result dialog, the strap voltage on the Devices card, and the field-mapping capture diff. - WhoopProtocol: ExtendedBatteryProbe.format(...) — the pure formatter (verdict, full raw hex, offset-labelled payload grid, decoded voltage, per-byte capture diff). Placed in the package (not app-side like Kotlin) so swift test covers it on Linux/CI; behaviour is byte-identical to the Kotlin formatter. 5 tests pin it against the real 4.0 capture, the diff, a bare stub, and a 5/MG UNSUPPORTED verdict. - BLEManager: probeExtendedBatteryInfo() (+ 8s no-reply timeout, guard-then-set is race-free since BLE callbacks + the timer both run on main), clearExtended..., the frame[6] (4.0) and frame[10] (5/MG) COMMAND_RESPONSE dumps, the 5/MG allowlist entry for 98, prev-payload persisted in UserDefaults (noop.592.prevPayload). - LiveState: batteryMv + extendedBatteryProbe (+ disconnect resets). - FrameRouter: consume battery_mV → state.batteryMv (event + command response). - AppModel: probeExtendedBatteryInfo()/clearExtendedBatteryProbe() forwards. - DevicesView: the probe menu item, a read-only confirm dialog, a copyable result sheet (selectable text + PlatformPasteboard Copy), and the voltage readout beside the battery percent. Design tokens only. Verified on Linux: WhoopProtocol builds + all 294 tests pass (incl. the 5 new); swiftc -parse clean on every app-target file. App-target compile (BLEManager / DevicesView / etc.) needs an app-build run — flagged. * iOS ryanbr#592 probe: localize the Devices probe/voltage strings (de/es/fr) Parity fix for the Android side (ryanbr#603/ryanbr#601 extracted these to strings.xml). The 8 new DevicesView UI strings — the probe menu item, confirm dialog title + message, Send/waiting/result-title, and the voltage readout + a11y label — were plain literals (English-only, and a i18n-gate failure). Extract them to Localizable.xcstrings with de/es/fr; the voltage uses SwiftUI specifier interpolation so the number localizes too. i18n audit --ci exit 0.
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.
Follow-up to #599. The probe currently writes its result only to the strap log, so reading or sharing a capture means exporting the whole log. This surfaces it in place — a result dialog you can read and copy straight into the issue.
What it adds
WhoopBleClient— publishes the probe result (raw hex + payload triage + the 5/MG result code) to a newextendedBatteryProbe: StateFlow<String?>alongside the existing log lines. A" waiting"sentinel is set when the probe is sent so the dialog can show an in-flight state until the reply lands;clearExtendedBatteryProbe()resets it.AppViewModel— exposes the flow + clear.DevicesScreen— when a result arrives, a read-only dialog shows the text (monospace, selectable, scrollable to 360dp) with a Copy button (LocalClipboardManager) and Close. So a capture pastes straight into GET_EXTENDED_BATTERY_INFO / ENTER-EXIT_HIGH_FREQ_SYNC: opcode mismatch between two independent RE sources (87/85/86 vs 98/96/97) #592 with no full-log export.strings.xml(+de/es/fr) — dialog title, the waiting line, Copy, Close.Notes
Verification
testFullDebugUnitTestgreen (StateFlow + UI only, no analytics logic touched);Tools/i18n_audit.py --ci mainexit 0 (4 new keys × de/es/fr, XML validated).