fix(locator): add a way to clear the active target

setTarget() always set locator_has_target=1; there was no path back to
"none" once a target was picked. Add a synthetic "(none)" entry that's
always first in the target picker/cycle set, backed by new
UITask::clearTarget().
This commit is contained in:
MarekZegare4
2026-06-24 22:52:19 +02:00
parent 15b89e2827
commit c726b2bb35
3 changed files with 23 additions and 7 deletions

View File

@@ -6,8 +6,9 @@
// of (leave/away) the radius. A waypoint target is snapshotted (coord + label);
// a person target follows their latest shared position. The crossing engine
// lives in UITask::evaluateLocator(). The Target row's Enter opens a picker
// (favourites first — offered even with no known position yet, so you can arm
// ahead of time — then any other contact with a currently-known position:
// ("None" first — the only way to unset a target once chosen — then
// favourites, offered even with no known position yet so you can arm ahead
// of time, then any other contact with a currently-known position:
// live-sharing or just last-advertised, e.g. a repeater; then waypoints).
// LEFT/RIGHT quick-cycles the same set. The same active target can also be set
// directly from Nearby Nodes' or Waypoints' own "Set as target" menu item
@@ -34,7 +35,7 @@ class LocatorScreen : public UIScreen {
bool _picking = false;
int _pick_sel = 0, _pick_scroll = 0;
struct Target {
uint8_t kind; // 0=waypoint 1=person
uint8_t kind; // 0=waypoint 1=person 2=none (clear target)
int32_t lat, lon;
uint8_t key[6];
char name[20];
@@ -170,7 +171,8 @@ public:
return true;
}
// Build the selectable target set into _targets: favourites first (the quick
// Build the selectable target set into _targets: "None" first (clears the
// target — the only way to unset it once chosen), then favourites (the quick
// path you pin ahead of time, offered even with no known position yet), then
// any other contact with a currently-known position — live-sharing or just
// last-advertised (a repeater, a room, or someone who shared a fix once) —
@@ -178,6 +180,10 @@ public:
// re-resolves their position each evaluation rather than trusting a snapshot.
void buildTargets() {
_target_n = 0;
Target& none = _targets[_target_n++];
none.kind = 2; none.lat = 0; none.lon = 0; none.ts = 0; none.live = false;
memset(none.key, 0, 6);
snprintf(none.name, sizeof(none.name), "(none)");
for (int i = 0; i < NodePrefs::FAVOURITES_COUNT; i++) {
const uint8_t* pre = _prefs->favourite_contacts[i];
bool empty = true;
@@ -203,7 +209,9 @@ public:
}
// Index of the currently-configured target within _targets, or -1.
// No target set at all maps to the synthetic "None" entry (always index 0).
int currentTargetIndex() const {
if (!_prefs->locator_has_target) return 0;
for (int i = 0; i < _target_n; i++) {
if (_targets[i].kind == 1 && _prefs->locator_target_kind == 1) {
if (memcmp(_targets[i].key, _prefs->locator_key, 6) == 0) return i;
@@ -216,6 +224,7 @@ public:
}
void applyTarget(const Target& t) {
if (t.kind == 2) { _task->clearTarget(); _dirty = true; return; }
// Same target definition as every other entry point (UITask::setTarget),
// but the save is deferred to screen exit (_dirty) so LEFT/RIGHT cycling
// through candidates doesn't write flash on each step.
@@ -223,10 +232,9 @@ public:
_dirty = true;
}
// LEFT/RIGHT quick-cycle over the same set the picker shows.
// LEFT/RIGHT quick-cycle over the same set the picker shows (includes "None").
void cycleTarget(int dir) {
buildTargets();
if (_target_n == 0) { _task->showAlert("No targets available", 1400); return; }
int cur = currentTargetIndex();
int nx = (cur < 0) ? (dir >= 0 ? 0 : _target_n - 1)
: ((cur + (dir >= 0 ? 1 : _target_n - 1)) % _target_n);
@@ -236,7 +244,6 @@ public:
void openPicker() {
if (!_prefs) return;
buildTargets();
if (_target_n == 0) { _task->showAlert("No targets available", 1400); return; }
int cur = currentTargetIndex();
_pick_sel = (cur >= 0) ? cur : 0;
_pick_scroll = 0;

View File

@@ -2375,6 +2375,12 @@ void UITask::setTargetNow(uint8_t kind, const uint8_t* key, int32_t lat, int32_t
showAlert("Target set", 1200);
}
void UITask::clearTarget() {
if (!_node_prefs) return;
_node_prefs->locator_has_target = 0;
resetLocator();
}
// Homing beeper: while armed with a target and inside the radius, emit a short
// tick whose interval shrinks linearly with distance — slow at the edge, rapid
// near the centre. Polls distance a few times a second; silent outside the

View File

@@ -204,6 +204,9 @@ public:
// such hook uses setTargetNow() to save + confirm on the spot.
void setTarget(uint8_t kind, const uint8_t* key, int32_t lat, int32_t lon, const char* name);
void setTargetNow(uint8_t kind, const uint8_t* key, int32_t lat, int32_t lon, const char* name);
// Unset the active target (locator_has_target = 0). Distinct from setTarget()
// because there's no "kind" for nothing — clearing is its own operation.
void clearTarget();
// Resolve a person target (6-byte pubkey prefix) to a current position:
// prefers an active [LOC] live share, falls back to their last-advertised
// GPS fix. Returns false when neither is known. Optional live/ts report