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
+8 -7
View File
@@ -747,18 +747,19 @@ public:
} else if (_page == HomePage::FAVOURITES) {
// Grid of pinned contacts. Layout transposes to current orientation:
// landscape → 3×2, portrait → 2×3. Selected tile inverts via drawSelectionRow.
// No title — node name + battery (top bar) and the page-dots indicator above
// serve as the page identity.
display.setColor(DisplayDriver::LIGHT);
display.setTextSize(1);
display.drawTextCentered(display.width() / 2, 0, "FAVOURITES");
display.fillRect(0, display.headerH() - 1, display.width(), display.sepH());
const int cols = display.isLandscape() ? 3 : 2;
const int rows = NodePrefs::FAVOURITES_COUNT / cols;
const int grid_y = display.headerH() + display.sepH();
const int grid_h = display.height() - grid_y;
const int margin = 2;
const int grid_y = content_y + margin;
const int grid_h = display.height() - grid_y - margin;
const int cell_w = display.width() / cols;
const int cell_h = grid_h / rows;
const int lh = display.getLineHeight();
const int line_h = display.getLineHeight();
if (_fav_sel >= NodePrefs::FAVOURITES_COUNT) _fav_sel = 0;
@@ -791,7 +792,7 @@ public:
char name[24];
if (found) display.translateUTF8ToBlocks(name, ci.name, sizeof(name));
else strncpy(name, "(gone)", sizeof(name) - 1), name[sizeof(name) - 1] = '\0';
int name_y = cy + (cell_h - lh) / 2;
int name_y = cy + (cell_h - line_h) / 2;
display.drawTextEllipsized(cx + 2, name_y, cell_w - 4, name);
if (found) {
@@ -805,7 +806,7 @@ public:
}
}
} else {
int plus_y = cy + (cell_h - lh) / 2;
int plus_y = cy + (cell_h - line_h) / 2;
display.drawTextCentered(cx + cell_w / 2, plus_y, "+");
}
if (sel) display.setColor(DisplayDriver::LIGHT);