Add Fahrenheit toggle for amplifier temperature#3652
Conversation
There was a problem hiding this comment.
Thanks for this, @haider855 — this is a well-executed contribution. The telemetry stays in Celsius and only converts at display time, the preference is persisted as one nested-JSON object under the AmpApplet key (Principle V), styling goes through ThemeManager::applyStyleSheet, and the conversion-rounding test cases (94.5/83.1 F, 32.0 F) are a nice touch. All six checks pass, including the Qt Accessibility static analysis.
A few notes, none blocking:
Verified, not a concern: The "True"/"False" string storage for the bool looked unusual at first, but it matches the established house convention — DisplaySettings.h does the exact same thing (o["leanMode"] = ... QStringLiteral("True") : QStringLiteral("False")). Consistent with the codebase, so leave it as is.
Nice catch: Adding m_hasTempA so the display shows the — placeholder until the first setTemp() (instead of a misleading 0.0 C) is a real improvement over the prior behavior.
Minor — i18n consistency: The tooltip, accessible name, and nextUnit strings are wrapped in tr(), but setAccessibleDescription("Toggles amplifier temperature between Celsius and Fahrenheit") is a raw literal. For consistency with the other user-facing strings on this widget, consider wrapping it in tr() too.
Optional — theme tokens (Principle IX): The button stylesheet hardcodes #00b4d8 for the focus border (the highlight colour) and #203040/#ffffff for hover. A recent commit (0d2622c) migrated hardcoded highlight/disabled colours to ThemeManager tokens. The adjacent telemetry labels in this same file still use raw hex, so you're consistent with the surrounding code and I wouldn't hold the PR for it — just flagging in case you'd like to pull the focus/hover colours from theme tokens while you're here.
Overall this looks good to me. Thanks for the clean tests and the accessibility handling (the QAccessible::NameChanged event on toggle is the right call).
🤖 aethersdr-agent · cost: $2.7796 · model: claude-opus-4-8
There was a problem hiding this comment.
Thanks for this, @haider855 — really nicely done. The scope is tight (just the applet, its header, the test, and the CMake target), telemetry stays in Celsius with conversion only at display time, the m_hasTempA placeholder handling is a good touch, and the accessibility wiring (setAccessibleName + QAccessibleEvent on NameChanged) is more thorough than most UI PRs. All six CI checks are green, including the a11y static analysis. The widget regression test covering default/single/dual/reload is exactly what this kind of change needs.
One substantive convention note, plus a minor one:
1. Store the preference as a native JSON bool, not a "True"/"False" string.
The nested-JSON-under-one-key approach is the right call (Principle V). But the value is being serialized as a string:
obj[kTempFahrenheitField] = enabled ? QStringLiteral("True") : QStringLiteral("False");
...
.value(kTempFahrenheitField).toString(QStringLiteral("False")) == QStringLiteral("True");The codebase convention for booleans inside a JSON settings object is a native JSON bool. The directly analogous applet, EqApplet, does:
cfg["showTx"] = m_showTx; // write (bool)
m_showTx = cfg.value("showTx").toBool(true); // readand MqttSettings does the same for its nested object (.toBool(false)). The "True"/"False" string form is what AppSettings uses for top-level flat XML keys (SmartSDR/.NET style), not for values nested in a JSON blob. Your code round-trips correctly as written, so this isn't a bug — but matching EqApplet would make it obj[kTempFahrenheitField] = enabled; and .toBool(false), which is simpler and consistent.
2. (Minor, optional) Theme tokens for the new hover/focus colors.
kBtnStyle in this file uses {{color.background.2}} / {{color.text.primary}} tokens, and recent work (commit 0d2622c, Principle IX) migrated hardcoded state colors to ThemeManager tokens. The new button's :hover/:focus borders (#203040, #00b4d8) are hardcoded. The base text color matches the existing kTelStyle it replaces, so the area is already mixed — just flagging in case there are tokens that fit, no need to block on it.
Neither is blocking from my side. Nice contribution.
🤖 aethersdr-agent · cost: $2.7019 · model: claude-opus-4-8
ten9876
left a comment
There was a problem hiding this comment.
Approving — clean, well-tested, CI green across all six, applies cleanly to main.
Verified: display-only C→F conversion (degC*9/5+32; telemetry stays Celsius), Principle-V persistence (nested AmpApplet JSON, read-modify-write), accessible toggle, and a new registered regression test. The unsigned commit is moot on squash-merge (GitHub signs the squash).
Note: this and #3651 both touch AmpApplet.cpp — merging this first means #3651 will need a rebase (handled separately). Nice work @haider855.
Summary
Fixes #3650
Adds a clickable Celsius/Fahrenheit toggle to the Amplifier pane temperature display. The amplifier telemetry remains stored in Celsius, and the applet converts only at display time. The selected unit is persisted with
AppSettingsunder theAmpAppletconfig object. Adds a widget regression test covering the default display, single-temp toggle, dual-temp toggle, and preference reload.Constitution principle honored
Principle V — the new UI preference is persisted as part of one owned
AmpAppletsettings object instead of adding scattered flat settings keys.Test plan
cmake --build build-local --target AetherSDR --parallel 4)ctest --test-dir build-local -R amp_applet_test --output-on-failure)amp_applet_test.Additional checks:
cmake --build build-local --target amp_applet_test --parallel 4python tools/check_a11y.py src/gui/AmpApplet.cppgit diff --checkChecklist
docs/COMMIT-SIGNING.md)AppSettingscalls — use nested-JSON-under-one-key (Principle V)MeterSmoother(AGENTS.md convention)