perf(l2): long lists build only the rows on screen

New message, Nodes (and its Scan popup), Admin and Messages show their
items through one virtual list: a screenful of rows, handed to the next
item as one scrolls out, the scroll extent from the items' heights. 256
contacts: 522 objects and ~950 ms of filling in (frames up to 96 ms)
before, 19 objects at once now; a scrolled frame 28.5 -> 11.7 ms. Nodes
257 -> 49 objects. A new message rewrites Messages' rows in place
(46 -> 20 ms) instead of building the screen again; it's rebuilt only
when "Read all" comes or goes. A held row keeps what it shows until let
go. Perf tools: -D PERF_LISTS, -D PERF_LIST_MUL.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-10-01 20:56:14 +02:00
co-authored by Claude Opus 5.5
parent 71e3dd8a8b
commit c8e1f4a604
7 changed files with 531 additions and 158 deletions
@@ -39,13 +39,20 @@ static void onMsgAction(lv_event_t* e) { s_ui->messageAction((uint8_t)(uintptr_t
static void onRoomLoginKb(lv_event_t* e) { s_ui->roomLoginDone(lv_event_get_code(e) == LV_EVENT_READY); }
static void onDMRowHold(lv_event_t* e) {
intptr_t r = vlist::arg(e);
if (r < 0 || !s_dm_known[r]) return; // no options for who isn't a contact
lv_indev_wait_release(lv_indev_active()); // the hold isn't also a tap that opens it
s_ui->conversationMenu(s_dm_rows[(uintptr_t)lv_event_get_user_data(e)]);
s_ui->conversationMenu(s_dm_rows[r]);
}
static void onRoomRow(lv_event_t* e) {
intptr_t r = vlist::arg(e);
if (r >= 0) s_ui->openRoom(s_room_rows[r]);
}
static void onRoomRow(lv_event_t* e) { s_ui->openRoom(s_room_rows[(uintptr_t)lv_event_get_user_data(e)]); }
static void onRoomRowHold(lv_event_t* e) {
intptr_t r = vlist::arg(e);
if (r < 0) return;
lv_indev_wait_release(lv_indev_active());
s_ui->conversationMenu(s_room_rows[(uintptr_t)lv_event_get_user_data(e)]);
s_ui->conversationMenu(s_room_rows[r]);
}
static void onConvThreadMenu(lv_event_t* e) { (void)e; s_ui->conversationMenu(nullptr); }
static void onMsgHold(lv_event_t* e) {
@@ -120,7 +127,7 @@ void UITask::roomPoll() {
if (o == RoomSessions::LOGGED_IN) {
showToast("Logged in", 1200);
if (mine && picking) openDM(s_login_key);
else if (_screen == SCR_CHATS && !_nav_overlay) buildChats();
else if (_screen == SCR_CHATS && !_nav_overlay) refreshChats();
} else if (o == RoomSessions::LOGIN_FAILED) {
showToast("Login failed - wrong password?", 3000);
if (mine && picking) roomLoginPopup(s_login_key);
@@ -383,5 +390,5 @@ void UITask::toggleChatFilter(uint8_t which) {
case CF_CONTACTS: _prefs->dm_show_all ^= 1; break;
}
prefsSave();
if (_screen == SCR_CONTACTS) buildContacts(); else buildChats();
if (_screen == SCR_CONTACTS) buildContacts(); else refreshChats();
}