refactor: one copy of shared logic and widgets; GPS is asked for, not switched on silently

Duplicates found between the L1 and L2 frontends, and inside the L2 one:
- geo::fmtLocShare / fmtLatLon / turnDeg / isAhead (GeoUtils.h): the [LOC]
  text was built in five places, the turn angle and its "ahead" threshold in
  both navigations, coordinates by hand in nine. Tested.
- LiveShareEngine::setEnabled: live share was switched in three places.
- L1 waypoint share uses WaypointModel::shareText; Trail's "Share my pos"
  goes through UITask::quickShareMyLocation, so it now sends to a running
  live-share session as the home Map page does.
- L2 Widgets.h: switchCreate (one switch size, was four), switchRow with a
  state and callback (16 hand-wired copies), switchRowOpens (Bluetooth, WiFi,
  GPS), primaryButton (one height for Save / Measure / New area / Update).

GPS: with it off, starting the trail, live share or track back, sharing or
marking a position, or centring the map asks first ("GPS is off") on both
L1 and L2; Cancel leaves it undone. A share or a mark waits for a fresh fix
(a switched-off module may still report its last one), which also fixes the
L1 "Share my pos" sending a stale position. SOS still turns the GPS on itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-11-02 10:32:23 +01:00
co-authored by Claude Opus 5.5
parent 781a480aef
commit ada5b8e545
35 changed files with 301 additions and 208 deletions
+2 -8
View File
@@ -58,12 +58,6 @@ static void botChip(const char* ph, void* parent) {
lv_obj_add_event_cb(b, onBotPlaceholder, LV_EVENT_CLICKED, NULL);
lv_obj_center(label(b, ph, THEME_FONT_SMALL, theme::TEXT));
}
// A switchRow() for something that isn't a plain pref: `cb` gets `idx`.
static void switchRowIdx(lv_obj_t* parent, const char* text, const char* hint, bool on, lv_event_cb_t cb, int idx) {
lv_obj_t* sw = switchRow(parent, text, hint, nullptr);
if (on) lv_obj_add_state(sw, LV_STATE_CHECKED);
lv_obj_add_event_cb(sw, cb, LV_EVENT_VALUE_CHANGED, (void*)(uintptr_t)idx);
}
static void onOpenBot(lv_event_t* e) { (void)e; s_ui->showBot(); }
static lv_obj_t* botHourButton(lv_obj_t* parent, const char* text, uint8_t act, bool accent) {
@@ -148,7 +142,7 @@ void UITask::buildBot() {
const botcfg::Row& r = botcfg::row(s_tab, i);
uint8_t* fl = botcfg::flag(p, r.kind);
if (fl && !botcfg::isScope(r.kind)) {
switchRowIdx(g, r.label, r.hint, *fl, onBotSwitch, i);
switchRow(g, r.label, r.hint, *fl, onBotSwitch, (void*)(uintptr_t)i);
continue;
}
uint16_t* cmd_off = botcfg::cmdOff(p, r.kind);
@@ -255,7 +249,7 @@ void UITask::botRow(int row) {
if (uint16_t* off = botcfg::cmdOff(p, r.kind)) {
lv_obj_t* g = group(scrollList(navPopupPanel("Allowed commands", true)), nullptr);
for (int i = 0; i < botcmd::count(botcfg::actionsOn(p, r.kind)); i++)
switchRowIdx(g, botcmd::CMDS[i].label, botcmd::CMDS[i].hint, !(*off & botcmd::flag(i)), onBotCmd, i);
switchRow(g, botcmd::CMDS[i].label, botcmd::CMDS[i].hint, !(*off & botcmd::flag(i)), onBotCmd, (void*)(uintptr_t)i);
return;
}