fix(home-pages): stop Favourites re-enabling on update; add Map visibility toggle

The prefs schema-migration block runs on every SCHEMA_SENTINEL mismatch, and
the "turn Favourites on" step was ungated. Since each firmware release bumps
the sentinel, every update re-applied `home_pages_mask |= HP_FAVOURITES`,
clobbering a user who had hidden it. Gate it to the transition that added
Favourites (sentinel < 0xC0DE0002), matching the trail_units_idx migration.

The Map/Trail carousel page shipped with no visibility toggle: pageBit(MAP)
returned -1 so it was always visible with no Settings row. Add a proper "Map"
toggle (new HPB_MAP/HP_MAP bit, pageBit/bitToPage cases, HOME_MAP settings
row) plus a gated one-time migration (sentinel < 0xC0DE0018) that keeps it
visible for upgraders. Bump SCHEMA_SENTINEL to 0xC0DE0018; page_order[] stays
a literal 11 so the persisted layout is unchanged.

Also fix the fresh-install seed, which used a stale 0x01FF literal that left
Favourites hidden on new installs despite its "all pages visible" comment;
seed NodePrefs::HP_ALL so fresh installs match upgraders (Favourites + Map).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MarekZegare4
2026-07-02 10:34:38 +02:00
parent 7e0dbe4afc
commit 088bbe61ba
5 changed files with 25 additions and 11 deletions

View File

@@ -469,12 +469,21 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
if (sentinel != NodePrefs::SCHEMA_SENTINEL) {
MESH_DEBUG_PRINTLN("prefs schema sentinel mismatch: got 0x%08X, expected 0x%08X — re-saving on next change",
(unsigned)sentinel, (unsigned)NodePrefs::SCHEMA_SENTINEL);
// 0xC0DE0001 → 0xC0DE0002: FAVOURITES home page added. Older saves have it
// implicitly off (their mask doesn't include HP_FAVOURITES); turn it on so
// upgraded users see the new page by default and can toggle it later.
if (_prefs.home_pages_mask != 0) {
// 0xC0DE0001 → 0xC0DE0002: FAVOURITES home page added. Only pre-0x0002 saves
// lack the bit; turn it on once so those upgraders see the new page by
// default. Must be gated to that transition — running it on every sentinel
// mismatch (as it did) re-enabled Favourites on each firmware update,
// clobbering a user who had deliberately hidden it.
if (sentinel < 0xC0DE0002 && _prefs.home_pages_mask != 0) {
_prefs.home_pages_mask |= NodePrefs::HP_FAVOURITES;
}
// 0xC0DE0017 → 0xC0DE0018: MAP home page moved into home_pages_mask (it was
// always-on before, with no visibility toggle). Turn its bit on once for
// pre-0x0018 saves so upgraders keep seeing the page; gated to this
// transition so a user who later hides it isn't overridden on the next update.
if (sentinel < 0xC0DE0018 && _prefs.home_pages_mask != 0) {
_prefs.home_pages_mask |= NodePrefs::HP_MAP;
}
// 0xC0DE0003 → 0xC0DE0004: trail_units_idx added after trail_min_delta_idx.
// On a 0xC0DE0003 file the sentinel bytes sit where trail_units_idx is now,
// so rd() picks up 0x03 (low byte of the old sentinel) — reset just that

View File

@@ -1504,7 +1504,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.ringtone2_bpm_idx = 2; // 120 bpm default
_prefs.notif_melody_ad = 0; // built-in advert sound by default
_prefs.advert_sound_scope = ADVERT_SOUND_SCOPE_ALL; // sound every advert by default
_prefs.home_pages_mask = 0x01FF; // all pages visible
_prefs.home_pages_mask = NodePrefs::HP_ALL; // all pages visible (incl. Favourites + Map)
_prefs.bot_enabled = 0;
_prefs.bot_channel_enabled = 0;
_prefs.bot_channel_idx = 0;

View File

@@ -344,7 +344,7 @@ struct NodePrefs { // persisted to file
// adding/removing/reordering fields in DataStore::savePrefs/loadPrefsInt so
// older saves are detected on load and skipped (zero-init defaults kept).
// High 24 bits identify the file format; low byte is the schema revision.
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0017;
static const uint32_t SCHEMA_SENTINEL = 0xC0DE0018;
// 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
@@ -362,7 +362,8 @@ struct NodePrefs { // persisted to file
HPB_SETTINGS = 9,
HPB_QUICK_MSG = 10,
HPB_FAVOURITES = 11,
HPB_COUNT = 12,
HPB_MAP = 12,
HPB_COUNT = 13,
};
// Length of the persisted page_order[] array. Stable across firmware versions
@@ -382,14 +383,15 @@ struct NodePrefs { // persisted to file
static const uint16_t HP_TOOLS = 1 << HPB_TOOLS;
static const uint16_t HP_SHUTDOWN = 1 << HPB_SHUTDOWN;
static const uint16_t HP_FAVOURITES = 1 << HPB_FAVOURITES;
static const uint16_t HP_ALL = 0x01FF | HP_FAVOURITES;
static const uint16_t HP_MAP = 1 << HPB_MAP;
static const uint16_t HP_ALL = 0x01FF | HP_FAVOURITES | HP_MAP;
// Label for home page by bit-index; returns "" for out-of-range.
// Array indices match HomePageBit values.
static const char* homePageLabel(uint8_t bit) {
static const char* labels[HPB_COUNT] = {
"Clock", "Recent", "Radio", "Bluetooth", "Advert",
"GPS", "Sensors", "Tools", "Shutdown", "Settings", "Messages", "Favourites"
"GPS", "Sensors", "Tools", "Shutdown", "Settings", "Messages", "Favourites", "Map"
};
return (bit < HPB_COUNT) ? labels[bit] : "";
}

View File

@@ -54,7 +54,7 @@ class SettingsScreen : public UIScreen {
HOME_SENSORS,
#endif
HOME_SETTINGS, HOME_QUICK_MSG,
HOME_TOOLS, HOME_SHUTDOWN,
HOME_TOOLS, HOME_SHUTDOWN, HOME_MAP,
// Radio section
SECTION_RADIO,
TX_POWER,
@@ -215,7 +215,7 @@ class SettingsScreen : public UIScreen {
return item == HOME_CLOCK || item == HOME_RECENT || item == HOME_RADIO ||
item == HOME_BT || item == HOME_ADVERT || item == HOME_TOOLS ||
item == HOME_SHUTDOWN || item == HOME_SETTINGS || item == HOME_QUICK_MSG ||
item == HOME_FAVOURITES
item == HOME_FAVOURITES || item == HOME_MAP
#if ENV_INCLUDE_GPS == 1
|| item == HOME_GPS
#endif
@@ -267,6 +267,7 @@ class SettingsScreen : public UIScreen {
#endif
if (item == HOME_TOOLS) return NodePrefs::HPB_TOOLS;
if (item == HOME_SHUTDOWN) return NodePrefs::HPB_SHUTDOWN;
if (item == HOME_MAP) return NodePrefs::HPB_MAP;
if (item == HOME_SETTINGS) return NodePrefs::HPB_SETTINGS;
if (item == HOME_QUICK_MSG) return NodePrefs::HPB_QUICK_MSG;
return -1;

View File

@@ -359,6 +359,7 @@ class HomeScreen : public UIScreen {
#endif
if (page == TOOLS) return NodePrefs::HPB_TOOLS;
if (page == SHUTDOWN) return NodePrefs::HPB_SHUTDOWN;
if (page == MAP) return NodePrefs::HPB_MAP;
return -1; // SETTINGS, QUICK_MSG always visible (no mask bit)
}
@@ -382,6 +383,7 @@ class HomeScreen : public UIScreen {
case NodePrefs::HPB_SHUTDOWN: return SHUTDOWN;
case NodePrefs::HPB_SETTINGS: return SETTINGS;
case NodePrefs::HPB_QUICK_MSG: return QUICK_MSG;
case NodePrefs::HPB_MAP: return MAP;
default: return -1;
}
}