fix(ui): Favourites page polish + upgrade migration

Render issues:
- Drop the "FAVOURITES" title — it overlapped the node-name/battery top
  bar; the page-dots indicator already identifies the page
- Use the locally-computed content_y (matches other home pages) so tiles
  sit below the dots row instead of starting at headerH() + sepH()
- Add 2 px top/bottom margin inside the grid so cells don't hug the dots
  or the panel edge

Upgrade migration (visibility + position):
- Newly-loaded prefs with an older sentinel OR a non-default mask had
  HP_FAVOURITES off and could not be enabled — DataStore::loadPrefsInt
  now ORs HP_FAVOURITES into home_pages_mask whenever the sentinel
  doesn't match the current schema
- Existing page_order_set users were stuck because FAVOURITES wasn't in
  page_order, so movePageInOrder bailed — ensurePageOrderInit now
  detects the missing FAVOURITES entry and inserts it right after CLOCK,
  shifting the tail; if the array is already full the page still
  appears via the buildVisibleOrder fallback

Bug fix in ensurePageOrderInit verification loop: iterated to HPB_COUNT
(12) over a PAGE_ORDER_LEN (11) array → one OOB read per call. Now
bounded to PAGE_ORDER_LEN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-05-24 23:17:48 +02:00
co-authored by Claude Sonnet 4.6
parent 63c5d99d7d
commit 66122e782d
3 changed files with 36 additions and 13 deletions
@@ -238,18 +238,34 @@ class SettingsScreen : public UIScreen {
}
// Initialises page_order to the default display sequence if not already set.
// Also repairs a partially-initialised order where CLOCK (bit 0, stored as 1) is absent.
// Also repairs a partially-initialised order where CLOCK is absent, and migrates
// older orders by inserting FAVOURITES after CLOCK so the page is reorderable.
void ensurePageOrderInit(NodePrefs* p) const {
if (!p) return;
if (p->page_order_set == NodePrefs::PAGE_ORDER_MAGIC) {
// Order was previously set — verify CLOCK is present to guard against partial/corrupted data.
for (int i = 0; i < NodePrefs::HPB_COUNT; i++) {
bool has_clock = false;
bool has_fav = false;
int len = 0;
int clock_at = -1;
for (int i = 0; i < NodePrefs::PAGE_ORDER_LEN; i++) {
uint8_t v = p->page_order[i];
if (v < 1 || v > NodePrefs::HPB_COUNT) break;
if (v == 0 + 1) return; // CLOCK found, order is intact
if ((int)(v - 1) == NodePrefs::HPB_CLOCK) { has_clock = true; clock_at = i; }
if ((int)(v - 1) == NodePrefs::HPB_FAVOURITES) { has_fav = true; }
len = i + 1;
}
if (!has_clock) {
// Corrupted/partial — full re-init below.
memset(p->page_order, 0, sizeof(p->page_order));
} else {
if (!has_fav && len < NodePrefs::PAGE_ORDER_LEN) {
// Insert FAVOURITES right after CLOCK; shift the tail down by one.
int insert_at = clock_at + 1;
for (int i = len; i > insert_at; i--) p->page_order[i] = p->page_order[i - 1];
p->page_order[insert_at] = NodePrefs::HPB_FAVOURITES + 1;
}
return;
}
// CLOCK missing — reset and fall through to full re-init.
memset(p->page_order, 0, sizeof(p->page_order));
}
// Default: CLOCK FAVOURITES RECENT RADIO BT ADVERT [GPS] [SENSORS] SETTINGS TOOLS MESSAGES
// SHUTDOWN is omitted from the explicit list (PAGE_ORDER_LEN = 11 leaves room for the