mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-11-02 19:02:00 +00:00
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:
@@ -1614,6 +1614,7 @@ public:
|
||||
display.setTextSize(1);
|
||||
display.drawTextCentered(display.width() / 2, content_y + step, "hibernating..."); // the panel's Hibernate row
|
||||
}
|
||||
if (_page == HomePage::MAP && _tile_menu.active) _tile_menu.render(display); // "GPS is off"
|
||||
if (slide >= 0) { // page turn: the page left behind slides out, this one in
|
||||
display.slideCompose(_slide_dir * (int)(display.width() * slide + 0.5f));
|
||||
anim_ms = 15;
|
||||
@@ -1634,6 +1635,14 @@ public:
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
// Map page: "GPS is off" before a share (the tile menu, free on this page).
|
||||
if (_page == HomePage::MAP && _tile_menu.active) {
|
||||
if (_tile_menu.handleInput(c) == PopupMenu::SELECTED && _tile_menu.selectedIndex() == 0) {
|
||||
_task->toggleGPS(false);
|
||||
_task->showAlert("GPS on, share once it has a fix", 1500);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Favourites grid claims joystick UP/DOWN and inner LEFT/RIGHT; LEFT at the
|
||||
// left column and RIGHT at the right column fall through to page nav so the
|
||||
// user can still leave the page sideways.
|
||||
@@ -1759,6 +1768,12 @@ public:
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_CONTEXT_MENU && _page == HomePage::MAP) {
|
||||
if (_task->hasGPS() && !_task->getGPSState()) { // its last fix may be stale: asked first
|
||||
_tile_menu.begin("GPS is off", 2);
|
||||
_tile_menu.addItem("Enable GPS");
|
||||
_tile_menu.addItem("Cancel");
|
||||
return true;
|
||||
}
|
||||
_task->quickShareMyLocation();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "InfoKit.h"
|
||||
#include "../NodePrefs.h"
|
||||
#include "icons.h" // drawList (shared scrolling-list helper)
|
||||
#include "PopupMenu.h" // "GPS is off" before Auto share starts
|
||||
|
||||
class LiveShareScreen : public UIScreen {
|
||||
UITask* _task;
|
||||
@@ -18,6 +19,7 @@ class LiveShareScreen : public UIScreen {
|
||||
bool _dirty = false;
|
||||
int _sel = 0;
|
||||
int _scroll = 0;
|
||||
PopupMenu _gps_ask;
|
||||
|
||||
enum Kind : uint8_t { K_TRACK, K_AUTO, K_DURATION, K_TARGET, K_SCOPE, K_MOVE, K_GAP, K_HB };
|
||||
struct Row { Kind kind; const char* label; };
|
||||
@@ -39,7 +41,7 @@ class LiveShareScreen : public UIScreen {
|
||||
public:
|
||||
LiveShareScreen(UITask* task, NodePrefs* prefs) : _task(task), _prefs(prefs) {}
|
||||
|
||||
void onShow() override { _dirty = false; _sel = 0; _scroll = 0; }
|
||||
void onShow() override { _dirty = false; _sel = 0; _scroll = 0; _gps_ask.active = false; }
|
||||
|
||||
// Resolve the configured target's display name (channel name or contact name).
|
||||
void currentTargetName(char* buf, int n) {
|
||||
@@ -112,6 +114,7 @@ public:
|
||||
int mqr = info::listRow(display, y, r.label, val, sel, reserve);
|
||||
if (mqr > 0) mq_delay = mqr;
|
||||
});
|
||||
if (_gps_ask.active) _gps_ask.render(display);
|
||||
return (mq_delay > 0 && mq_delay < 500) ? mq_delay : 500;
|
||||
}
|
||||
|
||||
@@ -124,8 +127,14 @@ public:
|
||||
switch (rows(_sel).kind) {
|
||||
case K_TRACK: _prefs->track_shared_loc ^= 1; _dirty = true; break;
|
||||
case K_AUTO:
|
||||
_prefs->loc_share_enabled ^= 1;
|
||||
if (_prefs->loc_share_enabled) _task->restartLocShareSession();
|
||||
// With the GPS off nothing would go out: asked first, as Trail does.
|
||||
if (!_prefs->loc_share_enabled && _task->hasGPS() && !_task->getGPSState()) {
|
||||
_gps_ask.begin("GPS is off", 2); // the action first, as Trail's: nothing is lost
|
||||
_gps_ask.addItem("Enable GPS & share");
|
||||
_gps_ask.addItem("Cancel");
|
||||
return;
|
||||
}
|
||||
_task->core().live_share.setEnabled(!_prefs->loc_share_enabled);
|
||||
_dirty = true; break;
|
||||
case K_DURATION:
|
||||
_prefs->loc_share_duration_idx = (uint8_t)((_prefs->loc_share_duration_idx + (dir >= 0 ? 1 : NodePrefs::LOC_SHARE_DURATION_COUNT - 1)) % NodePrefs::LOC_SHARE_DURATION_COUNT);
|
||||
@@ -192,6 +201,15 @@ public:
|
||||
}
|
||||
|
||||
bool handleInput(char c) override {
|
||||
if (_gps_ask.active) {
|
||||
if (_gps_ask.handleInput(c) == PopupMenu::SELECTED && _gps_ask.selectedIndex() == 0) {
|
||||
_task->toggleGPS(false);
|
||||
_task->core().live_share.setEnabled(true);
|
||||
_dirty = true;
|
||||
_task->showAlert("GPS on, sharing", 1200);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (c == KEY_CANCEL) {
|
||||
_task->savePrefsIfDirty(_dirty);
|
||||
_task->leaveTool();
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
namespace navview {
|
||||
|
||||
static const int AHEAD_DEG = 12; // within this of straight on: "ahead"
|
||||
|
||||
// own_valid : is there a usable GPS fix for the device right now
|
||||
// cog_valid : is there a stable course-over-ground (UITask::currentCourse)
|
||||
// eta : optional closing-speed/ETA tracker; when supplied a third line is
|
||||
@@ -89,8 +87,8 @@ inline void draw(DisplayDriver& d,
|
||||
}
|
||||
}
|
||||
int turn = 0; // -180..179 degrees to turn, right positive; with a course
|
||||
if (cog_valid) turn = ((to_deg - cog_deg + 540) % 360) - 180;
|
||||
const bool ahead = cog_valid && turn <= AHEAD_DEG && turn >= -AHEAD_DEG;
|
||||
if (cog_valid) turn = geo::turnDeg(to_deg, cog_deg);
|
||||
const bool ahead = cog_valid && geo::isAhead(turn);
|
||||
|
||||
// Distance — emphasised at size 2.
|
||||
d.setTextSize(2);
|
||||
|
||||
@@ -861,7 +861,7 @@ class NearbyScreen : public UIScreen, protected NearbyModel {
|
||||
// row, unlabelled: then there are five rows either way.
|
||||
const bool one_pos = top + step * 5 + display.getLineHeight() > bottom;
|
||||
if (one_pos) {
|
||||
snprintf(buf, sizeof(buf), "%.5f,%.5f", e.lat_e6 / 1e6, e.lon_e6 / 1e6);
|
||||
geo::fmtLatLon(buf, sizeof(buf), e.lat_e6, e.lon_e6);
|
||||
display.drawTextEllipsized(tx, top, w - 4, buf);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "Lat: %.5f", e.lat_e6 / 1e6);
|
||||
|
||||
@@ -964,7 +964,7 @@ public:
|
||||
} else if (sel == 0) { // Type in
|
||||
int32_t lat, lon;
|
||||
char cur[32] = "";
|
||||
if (_task->core().fixedPosition(lat, lon)) snprintf(cur, sizeof(cur), "%.5f, %.5f", lat / 1e6, lon / 1e6);
|
||||
if (_task->core().fixedPosition(lat, lon)) geo::fmtLatLon(cur, sizeof(cur), lat, lon, true);
|
||||
_edit_pos = true;
|
||||
_kb->begin(cur, 31);
|
||||
_kb->prompt = "Lat, lon";
|
||||
|
||||
@@ -81,7 +81,7 @@ class TrailScreen : public UIScreen {
|
||||
// correctly (settings rows cycle with LEFT/RIGHT; everything else is Enter).
|
||||
// Live-share *config* lives in its own tool (Tools › Live Share); the map only
|
||||
// keeps the one-shot "Share my pos" action.
|
||||
enum MenuLevel { ML_MAIN, ML_FILE, ML_SETTINGS, ML_CONFIRM_GPS, ML_CONFIRM_RESET };
|
||||
enum MenuLevel { ML_MAIN, ML_FILE, ML_SETTINGS, ML_CONFIRM_GPS, ML_CONFIRM_GPS_SHARE, ML_CONFIRM_RESET };
|
||||
PopupMenu _action_menu;
|
||||
uint8_t _menu_level = ML_MAIN;
|
||||
uint8_t _act_map[16]; // max rows on any one level; pushAction guards the cap
|
||||
@@ -179,6 +179,11 @@ public:
|
||||
_menu_level = ML_MAIN; // popup already closed by handleInput()
|
||||
return true;
|
||||
}
|
||||
if (_menu_level == ML_CONFIRM_GPS_SHARE) { // "Enable GPS": a fix takes a while, so no send yet
|
||||
if (_action_menu.selectedIndex() == 0) { _task->toggleGPS(false); _task->showAlert("GPS on, share once it has a fix", 1500); }
|
||||
_menu_level = ML_MAIN;
|
||||
return true;
|
||||
}
|
||||
// Reset confirmation popup: same shape, but defaults to Cancel (row 1)
|
||||
// since unlike the GPS prompt above, this one is destructive.
|
||||
if (_menu_level == ML_CONFIRM_RESET) {
|
||||
@@ -198,13 +203,16 @@ public:
|
||||
case ACT_MARK_AVG:
|
||||
case ACT_AUTOSAVE:
|
||||
case ACT_AUTOPAUSE: return true;
|
||||
case ACT_SHARE_NOW: shareMyLocationNow(); break;
|
||||
case ACT_SHARE_NOW:
|
||||
if (_task->hasGPS() && !_task->getGPSState()) { buildGpsConfirmMenu(true); return true; } // its last fix may be stale
|
||||
shareMyLocationNow();
|
||||
break;
|
||||
case ACT_TOGGLE:
|
||||
// Starting a trail with GPS switched off logs nothing and just
|
||||
// sits on "Waiting for GPS fix" forever -- prompt to enable it
|
||||
// first (only on boards that actually have a toggleable GPS).
|
||||
if (!_store->isActive() && _task->hasGPS() && !_task->getGPSState()) {
|
||||
buildGpsConfirmMenu();
|
||||
buildGpsConfirmMenu(false);
|
||||
return true;
|
||||
}
|
||||
handleToggle();
|
||||
@@ -379,13 +387,14 @@ private:
|
||||
pushAction(ACT_SETTINGS, "Settings...");
|
||||
}
|
||||
|
||||
// Confirmation shown when "Start tracking" is chosen with GPS off. Rows are
|
||||
// plain (not ActionIds); handled by _menu_level in the SELECTED branch.
|
||||
void buildGpsConfirmMenu() {
|
||||
_menu_level = ML_CONFIRM_GPS;
|
||||
// Confirmation shown when "Start tracking" or "Share my pos" is chosen with
|
||||
// GPS off. Rows are plain (not ActionIds); handled by _menu_level in the
|
||||
// SELECTED branch.
|
||||
void buildGpsConfirmMenu(bool share) {
|
||||
_menu_level = share ? ML_CONFIRM_GPS_SHARE : ML_CONFIRM_GPS;
|
||||
_act_count = 0;
|
||||
_action_menu.begin("GPS is off", 2);
|
||||
_action_menu.addItem("Enable GPS & start");
|
||||
_action_menu.addItem(share ? "Enable GPS" : "Enable GPS & start");
|
||||
_action_menu.addItem("Cancel");
|
||||
}
|
||||
|
||||
@@ -471,16 +480,8 @@ private:
|
||||
p->gps_avg_idx = idx;
|
||||
}
|
||||
|
||||
// One-shot manual share: build "[LOC]lat,lon" and hand it to the Messages
|
||||
// screen, where the user picks a DM or channel recipient. (Auto live-share
|
||||
// config lives in Tools › Live Share.)
|
||||
void shareMyLocationNow() {
|
||||
int32_t lat, lon;
|
||||
if (!_task->currentLocation(lat, lon)) { _task->showAlert("No GPS fix", 1000); return; }
|
||||
char text[40];
|
||||
snprintf(text, sizeof(text), LOCATION_MSG_TAG "%.5f,%.5f", lat / 1e6, lon / 1e6);
|
||||
_task->shareToMessage(text);
|
||||
}
|
||||
// One-shot manual share, as the home Map page's: UITask::quickShareMyLocation.
|
||||
void shareMyLocationNow() { _task->quickShareMyLocation(); }
|
||||
|
||||
// Render the average speed (or pace) in the globally-selected unit system.
|
||||
void formatAvgPaceOrSpeed(char* buf, size_t n, NodePrefs* p) const {
|
||||
|
||||
@@ -1907,7 +1907,6 @@ bool UITask::currentCourse(int& deg_out) const { return _core->course.currentCou
|
||||
bool UITask::currentLocation(int32_t& lat, int32_t& lon) const { return _core->course.currentLocation(lat, lon); }
|
||||
|
||||
bool UITask::sendLocationShare(int32_t lat, int32_t lon) { return _core->live_share.send(lat, lon); }
|
||||
void UITask::restartLocShareSession() { _core->live_share.restartSession(); }
|
||||
void UITask::restartLocShareClock() { _core->live_share.restartClock(); }
|
||||
LiveTrackStore& UITask::liveTrack() { return _core->live_share.track(); }
|
||||
|
||||
@@ -1923,7 +1922,7 @@ void UITask::quickShareMyLocation() {
|
||||
return;
|
||||
}
|
||||
char text[40];
|
||||
snprintf(text, sizeof(text), LOCATION_MSG_TAG "%.5f,%.5f", lat / 1e6, lon / 1e6);
|
||||
geo::fmtLocShare(text, sizeof(text), lat, lon);
|
||||
shareToMessage(text);
|
||||
}
|
||||
|
||||
|
||||
@@ -366,7 +366,6 @@ public:
|
||||
void gotoLiveShareScreen();
|
||||
// Live share session control (ui-core/LiveShareEngine.h): restart = new
|
||||
// session (re-announce + fresh clock); clock-only = changed "Stop after".
|
||||
void restartLocShareSession();
|
||||
void restartLocShareClock();
|
||||
void gotoLocatorScreen();
|
||||
// Re-arm the locator state machine so the next evaluation initialises
|
||||
|
||||
@@ -388,11 +388,8 @@ public:
|
||||
}
|
||||
} else if (sel == 2) { // Send (share in a message)
|
||||
if (wi >= 0 && wi < _task->waypoints().count()) {
|
||||
const Waypoint& w = _task->waypoints().at(wi);
|
||||
double lat = w.lat_1e6 / 1000000.0, lon = w.lon_1e6 / 1000000.0;
|
||||
char text[80];
|
||||
if (w.label[0]) snprintf(text, sizeof(text), WAYPOINT_MSG_TAG "%.5f,%.5f %s", lat, lon, w.label);
|
||||
else snprintf(text, sizeof(text), WAYPOINT_MSG_TAG "%.5f,%.5f", lat, lon);
|
||||
_task->core().waypoints.shareText(wi, text, sizeof(text));
|
||||
_task->shareToMessage(text); // hands off to the Messages screen
|
||||
}
|
||||
} else { // Set as target
|
||||
|
||||
Reference in New Issue
Block a user