mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-14 15:16:40 +00:00
feat(companion): contact expiry + prune, and scope-list follow-up fixes
Settings > Contacts gains "Expire" (Off/7d/30d/90d) and a "Prune now" action
that counts first and asks before removing anything. A contact with no
advert/update within the threshold is eligible; favourites are always kept.
Thresholds and their labels live in one NodePrefs table so the age shown and
the age enforced can't drift. SCHEMA_SENTINEL -> 0xC0DE002C (sizeof unchanged
at 2824, confirmed on native and a real WioTrackerL1 build).
Also fixes four bugs in the scope list from 89c02eea:
- removeScope() saved /scopes1 but never savePrefs(), so the ch_scope_idx[]
and repeat_extra_scope_mask fix-ups it makes were lost on reboot, leaving
shifted entries against unshifted indices.
- CMD_SET_DEFAULT_FLOOD_SCOPE wrote the legacy fields directly instead of
going through setPrimaryScope(), so the app's default-scope setting had
nothing reading it once sends resolved through the list.
- The reverse direction was stale too: an on-device "Set as default" never
refreshed default_scope_name/key, so CMD_GET_DEFAULT_FLOOD_SCOPE reported
a scope the device had stopped using. New syncLegacyDefaultScope().
- Upgrading from the old single Scope field set the default (so DMs kept it)
but left every channel unscoped, since "*" means unscoped, not "inherit".
loadScopeList() now reports when it migrated and begin() seeds the channels
that already exist, leaving empty slots alone.
"Set default" -> "Set as default", and setting it now says what it governs
("Default: DMs + relay") rather than leaving the [default] marker to imply
more than it does.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -498,6 +498,13 @@ struct NodePrefs { // persisted to file
|
||||
// memset and an older prefs file (no bytes here at all) mean "on", which is
|
||||
// the default -- a positive flag would read back as off for every upgrader.
|
||||
uint8_t fav_sort_off; // 0 = favourites first in every list (default), 1 = natural order
|
||||
// Settings > Contacts > "Expire" + "Prune now". Index into
|
||||
// contactExpiryDays()/contactExpiryLabel() below (0=Off/never, 1=7d, 2=30d,
|
||||
// 3=90d) -- a contact whose ContactInfo::lastmod is older than this is
|
||||
// eligible for the manual Prune-now sweep. Favourites are always exempt
|
||||
// regardless of age. On-disk position is the struct's append-only tail (see
|
||||
// the serialization tripwire below), same as fav_sort_off above.
|
||||
uint8_t contact_expiry_idx; // 0 = off (default)
|
||||
|
||||
// ── Advert ─────────────────────────────────────────────────────────────
|
||||
uint8_t advert_loc_policy;
|
||||
@@ -579,6 +586,21 @@ struct NodePrefs { // persisted to file
|
||||
// tuning only — not persisted.
|
||||
static const uint16_t TRAIL_AUTOPAUSE_MOVE_M = 15;
|
||||
|
||||
// Contact-expiry thresholds (days) for contact_expiry_idx. Single source of
|
||||
// truth for both the Settings > Contacts "Expire" row's label and the age
|
||||
// MyMesh::countStaleContacts()/pruneStaleContacts() actually applies, so the
|
||||
// number the user picks and the one enforced can't drift apart. 0 = off,
|
||||
// which is also the clamp target for any out-of-range saved index.
|
||||
static const uint8_t CONTACT_EXPIRY_COUNT = 4;
|
||||
static uint16_t contactExpiryDays(uint8_t idx) {
|
||||
static const uint16_t D[CONTACT_EXPIRY_COUNT] = { 0, 7, 30, 90 };
|
||||
return D[idx < CONTACT_EXPIRY_COUNT ? idx : 0];
|
||||
}
|
||||
static const char* contactExpiryLabel(uint8_t idx) {
|
||||
static const char* L[CONTACT_EXPIRY_COUNT] = { "Off", "7d", "30d", "90d" };
|
||||
return L[idx < CONTACT_EXPIRY_COUNT ? idx : 0];
|
||||
}
|
||||
|
||||
// Tail sentinel written at the end of /new_prefs. Bump the low byte when
|
||||
// adding/removing/reordering fields in DataStore::savePrefs/loadPrefsInt so
|
||||
// older saves are detected on load and skipped (zero-init defaults kept).
|
||||
@@ -588,7 +610,7 @@ struct NodePrefs { // persisted to file
|
||||
// repeat_* fields) instead of at the tail, which shifted every field after
|
||||
// them by 25 bytes when loading an older file. Never released, but a dev
|
||||
// build wrote it, so the number must not be reused for anything else.
|
||||
static const uint32_t SCHEMA_SENTINEL = 0xC0DE002B;
|
||||
static const uint32_t SCHEMA_SENTINEL = 0xC0DE002C;
|
||||
|
||||
// Bit-index for each home page. Used by page_order (entries store bit+1) and
|
||||
// by home_pages_mask. Single source of truth — both HomeScreen::pageBit/bitToPage
|
||||
@@ -733,6 +755,10 @@ struct NodePrefs { // persisted to file
|
||||
// earlier bump -- confirmed via a real sim_companion_radio (native) build
|
||||
// and a real WioTrackerL1_companion_solo_dual (nRF52/ARM) build, sizeof
|
||||
// 2824 on both.
|
||||
// contact_expiry_idx (0xC0DE002C) landed in existing padding elsewhere in
|
||||
// the struct -- confirmed via a real sim_companion_radio (native) build and a
|
||||
// real WioTrackerL1_companion_solo_dual (nRF52/ARM) build, sizeof unchanged
|
||||
// at 2824 on both.
|
||||
static_assert(sizeof(NodePrefs) == 2824,
|
||||
"NodePrefs layout changed — sync DataStore save/load + clamp, bump "
|
||||
"SCHEMA_SENTINEL, then update this size (see steps above).");
|
||||
|
||||
Reference in New Issue
Block a user