From 088bbe61ba7f89fe40de974045c9cce5e045016f Mon Sep 17 00:00:00 2001 From: MarekZegare4 Date: Thu, 2 Jul 2026 10:34:38 +0200 Subject: [PATCH] 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 --- examples/companion_radio/DataStore.cpp | 17 +++++++++++++---- examples/companion_radio/MyMesh.cpp | 2 +- examples/companion_radio/NodePrefs.h | 10 ++++++---- .../companion_radio/ui-new/SettingsScreen.h | 5 +++-- examples/companion_radio/ui-new/UITask.cpp | 2 ++ 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index b8a5ad7e..c0402c3d 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -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 diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index d0f33f6c..82940377 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -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; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 972392a5..d28408d3 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -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] : ""; } diff --git a/examples/companion_radio/ui-new/SettingsScreen.h b/examples/companion_radio/ui-new/SettingsScreen.h index b8322acf..82a54986 100644 --- a/examples/companion_radio/ui-new/SettingsScreen.h +++ b/examples/companion_radio/ui-new/SettingsScreen.h @@ -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; diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 5e5a28b7..5372e7c6 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -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; } }