mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-28 05:24:22 +00:00
fix(chat): cap rendered bubble text so large messages don't crawl on scroll
A message with multi-KB content (e.g. a large bz2-delivered payload) rendered untruncated, so LVGL laid it out as a 50+ line wrapped bubble and re-drew the whole thing while scrolling past it -- crawling the UI. Cap the *displayed* text to MAX_DISPLAY_CHARS; the full content stays stored. (Decompression is unrelated: it happens once in Resource::assemble() at receive, content is saved already decompressed, and load_message_metadata never re-decompresses.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UWZuYkHBRqNb6BZHV8sTG5
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
13b3d7d73a
commit
28c40de3a1
@@ -410,6 +410,13 @@ void ChatScreen::create_message_bubble(const MessageItem& item) {
|
||||
build_status_text(status_text, sizeof(status_text), item.timestamp_str,
|
||||
item.outgoing, item.delivered, item.failed);
|
||||
|
||||
// Cap very long messages for display — laying out and re-drawing a multi-KB
|
||||
// wrapped bubble is slow and memory-heavy. The full content stays stored.
|
||||
String display_text = item.content;
|
||||
if (display_text.length() > MAX_DISPLAY_CHARS) {
|
||||
display_text = display_text.substring(0, MAX_DISPLAY_CHARS) + "...";
|
||||
}
|
||||
|
||||
// Calculate text widths to decide layout
|
||||
// Bubble is 80% of 320 = 256px, minus 16px padding = 240px usable
|
||||
const lv_coord_t bubble_inner_width = 240;
|
||||
@@ -417,7 +424,7 @@ void ChatScreen::create_message_bubble(const MessageItem& item) {
|
||||
const lv_coord_t gap = 12; // Space between message and timestamp
|
||||
|
||||
lv_coord_t msg_width = lv_txt_get_width(
|
||||
item.content.c_str(), item.content.length(), font, 0, LV_TEXT_FLAG_NONE);
|
||||
display_text.c_str(), display_text.length(), font, 0, LV_TEXT_FLAG_NONE);
|
||||
lv_coord_t status_width = lv_txt_get_width(
|
||||
status_text, strlen(status_text), font, 0, LV_TEXT_FLAG_NONE);
|
||||
|
||||
@@ -431,7 +438,7 @@ void ChatScreen::create_message_bubble(const MessageItem& item) {
|
||||
|
||||
// Message content
|
||||
lv_obj_t* label_content = lv_label_create(bubble);
|
||||
lv_label_set_text(label_content, item.content.c_str());
|
||||
lv_label_set_text(label_content, display_text.c_str());
|
||||
lv_obj_set_style_text_color(label_content, lv_color_white(), 0);
|
||||
|
||||
// Timestamp on same row
|
||||
@@ -446,7 +453,7 @@ void ChatScreen::create_message_bubble(const MessageItem& item) {
|
||||
|
||||
// Message content with wrapping
|
||||
lv_obj_t* label_content = lv_label_create(bubble);
|
||||
lv_label_set_text(label_content, item.content.c_str());
|
||||
lv_label_set_text(label_content, display_text.c_str());
|
||||
lv_label_set_long_mode(label_content, LV_LABEL_LONG_WRAP);
|
||||
lv_obj_set_width(label_content, LV_PCT(100));
|
||||
lv_obj_set_style_text_color(label_content, lv_color_white(), 0);
|
||||
|
||||
@@ -192,6 +192,11 @@ private:
|
||||
static constexpr size_t MESSAGES_PER_PAGE = 10; // full first page (filled in background)
|
||||
static constexpr size_t BG_FILL_BATCH = 2; // older messages streamed per tick
|
||||
static constexpr size_t MAX_DISPLAYED_MESSAGES = 50; // Cap to prevent memory exhaustion
|
||||
// Cap the text rendered per bubble. LVGL lays out (and re-draws on scroll) a
|
||||
// wrapped label in O(length); a multi-KB message (e.g. a large bz2-delivered
|
||||
// payload) becomes a 50+ line bubble that crawls when scrolled past. The full
|
||||
// content stays stored; only the rendered text is truncated.
|
||||
static constexpr size_t MAX_DISPLAY_CHARS = 600;
|
||||
bool _loading_more; // Prevent concurrent loads
|
||||
// Streaming state. _bg_fill_active is atomic because on_scroll() (LVGL task)
|
||||
// and refresh() may set it while tick_background_fill() (main loop) reads it;
|
||||
|
||||
Reference in New Issue
Block a user