mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-08-03 10:46:12 +00:00
feat(companion): live location sharing, Locator geofencing, trail auto-pause
Squash merge of feat/location-beacon-alerts-autopause (v1.21). Features: - Live Location Sharing — broadcast position as movement-gated [LOC] messages to a channel or contact; live shares show as map pins with distance/bearing in Nearby Nodes and a status-bar indicator. [LOC] is parsed in DMs, channel messages and room messages; DM shares name the sender. - Locator (geofence) — arm a geofence around a saved waypoint or a person (live [LOC] or last-known position), alert on arrive/leave or near/far, with an optional homing beeper (gated to arrive/both modes). Arm from Tools > Locator, Nearby Nodes, or Waypoints; target picker lists favourites first, clearable via a "None" entry. Active target is drawn as a flag on the map. - One active target shared across Locator / Navigate / Map via a single resolver (resolvePersonPos / activeTargetPos) that prefers a live [LOC] share over the last-advertised GPS fix. - Follow live contacts — Navigate to a live-sharing contact follows them as they move and adds an ETA line; quick-share your own position from the Map. - Map & status-bar upgrades — home mini-map gets a north marker, scale tick, and a connected trail line (was disconnected dots); status line shows tracked-node count, an arrow + distance to the active Locator/Nav target (falling back to the nearest live-tracked contact); GPS fix icon in the top status bar, shown only on GPS boards with GPS enabled. - Trail auto-pause — recording freezes on stops (banking elapsed time, breaking the map line across the idle gap) and resumes on movement without ending the session. - Streaming trail simplification — GPS points are simplified in-stream via a fixed-corridor (Reumann-Witkam) pass tuned for fidelity: straight runs collapse to their endpoints, curves stay bounded to the Min-dist tolerance, so the 512-point buffer covers a far longer route than a flat point budget would suggest. - Collapsible Tools (Location / Comms / System sections, fold-in-place like Settings) and page-indicator icons on the home carousel. - Waypoint coordinate editor — add a waypoint by scroll-editing lat/lon digit by digit. Fixes: - Critical: low-heap hang and contact loss on RAM-tight builds. Halved message-history scrollback rings (recovering ~14 KB free heap) and made contacts/channels/prefs persistence atomic (temp file + rename), so an interrupted save can no longer corrupt or wipe the store. - Serial.write() bounded so a stalled USB host can't hang the device. - Nearby Nodes: live [LOC] senders respect the type filter, sort by shared position, and the list refreshes so live shares bubble up. - Map: live contacts are labelled before waypoints. - GPS status icon hidden when GPS is off in Settings. - Splash screen no longer truncates a pre-release tag's own dash (e.g. v1.21-rc1) when stripping the build's commit-hash suffix. - Null-guarded the Locator target picker; clamped loc-share channel index on load. Under the hood: - -Os size optimisation on the e-ink and GAT562 30S solo envs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c935287627
commit
57774d41f3
@@ -45,11 +45,12 @@ class QuickMsgScreen : public UIScreen {
|
||||
FullscreenMsgView _fs;
|
||||
int _unread_at_entry; // _ch_unread value when entering CHANNEL_HIST
|
||||
int _viewing_max_seen; // highest _hist_sel reached in current session
|
||||
// Shared ring for all channels combined. Sized to comfortably exceed
|
||||
// typical inter-visit accumulation; addChannelMsg() decrements the
|
||||
// Shared ring for all channels combined. addChannelMsg() decrements the
|
||||
// matching _ch_unread when an entry is evicted so the badge can't claim
|
||||
// unread messages that no longer exist in the ring.
|
||||
static const int CH_HIST_MAX = 96;
|
||||
// unread messages that no longer exist in the ring. Each slot carries a full
|
||||
// MSG_TEXT_BUF, so this ring dominates the screen's RAM footprint — kept
|
||||
// modest to leave heap headroom (see DM_HIST_MAX).
|
||||
static const int CH_HIST_MAX = 48;
|
||||
|
||||
// KEYBOARD
|
||||
KeyboardWidget* _kb;
|
||||
@@ -84,6 +85,9 @@ class QuickMsgScreen : public UIScreen {
|
||||
// in the keyboard to confirm/edit before sending.
|
||||
bool _share_mode = false;
|
||||
char _share_text[160] = "";
|
||||
// Live-share target picker: reuse the recipient chooser to set the persistent
|
||||
// auto-share target (channel / DM) instead of composing a message.
|
||||
bool _pick_target = false;
|
||||
|
||||
// History text holds a full received message. Channel messages carry the
|
||||
// sender embedded as "Name: body" in the payload, so a message can be up to
|
||||
@@ -123,7 +127,8 @@ class QuickMsgScreen : public UIScreen {
|
||||
uint8_t attempt; // last attempt number sent (outgoing); next resend = attempt+1
|
||||
uint8_t resends_left; // remaining auto-resends before the marker shows ✗
|
||||
};
|
||||
static const int DM_HIST_MAX = 64;
|
||||
// Each slot carries a full MSG_TEXT_BUF; kept modest to bound heap use.
|
||||
static const int DM_HIST_MAX = 32;
|
||||
DmHistEntry _dm_hist[DM_HIST_MAX];
|
||||
int _dm_hist_head, _dm_hist_count;
|
||||
int _dm_hist_sel, _dm_hist_scroll;
|
||||
@@ -834,6 +839,7 @@ public:
|
||||
_ctx_dirty = false;
|
||||
_nav_active = false;
|
||||
_share_mode = false;
|
||||
_pick_target = false;
|
||||
_pin_picker_active = false;
|
||||
_dm_direct_entry = false;
|
||||
_unread_at_entry = 0;
|
||||
@@ -881,6 +887,44 @@ public:
|
||||
_phase = MODE_SELECT;
|
||||
}
|
||||
|
||||
// Open the recipient chooser to set the live-share target (channel/DM). On
|
||||
// selection the target is stored in NodePrefs and the Map screen is restored.
|
||||
void startPickTarget() {
|
||||
reset();
|
||||
_pick_target = true;
|
||||
_phase = MODE_SELECT;
|
||||
}
|
||||
|
||||
void commitPickTargetChannel(int ch_idx) {
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
if (p) {
|
||||
p->loc_share_target_type = 0;
|
||||
p->loc_share_channel_idx = (uint8_t)ch_idx;
|
||||
the_mesh.savePrefs();
|
||||
}
|
||||
_pick_target = false;
|
||||
_task->showAlert("Share target set", 1200);
|
||||
_task->gotoLiveShareScreen();
|
||||
}
|
||||
|
||||
void commitPickTargetDM(const ContactInfo& ci) {
|
||||
// A room server can't be a live-share target — a [LOC] DM to it is never
|
||||
// reposted to the room's members. Reject the pick and keep the chooser open.
|
||||
if (ci.type == ADV_TYPE_ROOM) {
|
||||
_task->showAlert("Rooms not supported", 1400);
|
||||
return;
|
||||
}
|
||||
NodePrefs* p = _task->getNodePrefs();
|
||||
if (p) {
|
||||
p->loc_share_target_type = 1;
|
||||
memcpy(p->loc_share_dm_prefix, ci.id.pub_key, NodePrefs::FAVOURITE_PREFIX_LEN);
|
||||
the_mesh.savePrefs();
|
||||
}
|
||||
_pick_target = false;
|
||||
_task->showAlert("Share target set", 1200);
|
||||
_task->gotoLiveShareScreen();
|
||||
}
|
||||
|
||||
void enterDM(const ContactInfo& ci) {
|
||||
_sel_contact = ci;
|
||||
_task->clearDMUnread(ci.id.pub_key);
|
||||
@@ -1500,6 +1544,7 @@ public:
|
||||
if (c == KEY_DOWN && _num_contacts > 0) { _contact_sel = (_contact_sel < _num_contacts - 1) ? _contact_sel + 1 : 0; return true; }
|
||||
if (c == KEY_ENTER && _num_contacts > 0) {
|
||||
if (the_mesh.getContactByIdx(_sorted[_contact_sel], _sel_contact)) {
|
||||
if (_pick_target) { commitPickTargetDM(_sel_contact); return true; }
|
||||
_task->clearDMUnread(_sel_contact.id.pub_key);
|
||||
_dm_hist_sel = -1;
|
||||
_dm_hist_scroll = 0;
|
||||
@@ -1590,6 +1635,7 @@ public:
|
||||
if (c == KEY_DOWN && _num_channels > 0) { _channel_sel = (_channel_sel < _num_channels - 1) ? _channel_sel + 1 : 0; return true; }
|
||||
if (c == KEY_ENTER && _num_channels > 0) {
|
||||
_sel_channel_idx = _channel_indices[_channel_sel];
|
||||
if (_pick_target) { commitPickTargetChannel(_sel_channel_idx); return true; }
|
||||
int hc = histCountForChannel(_sel_channel_idx);
|
||||
_unread_at_entry = (int)_ch_unread[_sel_channel_idx];
|
||||
_hist_scroll = 0;
|
||||
|
||||
Reference in New Issue
Block a user