From 2ef3746c55a3d83bcfacb61842e41fe7b0152312 Mon Sep 17 00:00:00 2001 From: Pixel Perfect Date: Tue, 4 Aug 2026 10:31:40 -0700 Subject: [PATCH] feat(tpager): finish accessible chat sizing --- src/helpers/esp32/TouchPrefsStore.cpp | 10 +- src/helpers/esp32/TouchPrefsStore.h | 4 +- src/ui-touch/UITask.cpp | 158 ++++++++++++++++++-------- 3 files changed, 123 insertions(+), 49 deletions(-) diff --git a/src/helpers/esp32/TouchPrefsStore.cpp b/src/helpers/esp32/TouchPrefsStore.cpp index d2724fde..e0fb8cee 100644 --- a/src/helpers/esp32/TouchPrefsStore.cpp +++ b/src/helpers/esp32/TouchPrefsStore.cpp @@ -110,7 +110,7 @@ static void cfgSetDefaults(TouchCfg& c) { c.map_show_contacts = 1; c.app_grid_large = 0; // default: compact app grid (T-Deck 4 cols / V4 3 cols) #if defined(TLORA_PAGER) - c.ui_scale = 0; // Pager: Small/current typography by default + c.ui_scale = 0; // Pager: Default/current typography by default #else c.ui_scale = 1; // large-screen boards keep their existing 150% default #endif @@ -1015,11 +1015,19 @@ bool touchPrefsSetAppGridLarge(bool on) { uint8_t touchPrefsGetUiScale() { if (!s_begun) touchPrefsBegin(); +#if defined(TLORA_PAGER) + return s_cfg.ui_scale > 3 ? 0 : s_cfg.ui_scale; +#else return s_cfg.ui_scale > 2 ? 0 : s_cfg.ui_scale; +#endif } bool touchPrefsSetUiScale(uint8_t scale) { if (!s_begun) touchPrefsBegin(); +#if defined(TLORA_PAGER) + s_cfg.ui_scale = scale > 3 ? 0 : scale; +#else s_cfg.ui_scale = scale > 2 ? 0 : scale; +#endif return cfgFlush(); } diff --git a/src/helpers/esp32/TouchPrefsStore.h b/src/helpers/esp32/TouchPrefsStore.h index 06dee71d..651da561 100644 --- a/src/helpers/esp32/TouchPrefsStore.h +++ b/src/helpers/esp32/TouchPrefsStore.h @@ -155,8 +155,8 @@ bool touchPrefsSetAppGridLarge(bool on); bool touchPrefsGetSleepIdle(); bool touchPrefsSetSleepIdle(bool on); -/* UI-size preset, 0..2. Large-screen boards retain their percentage mapping; - * the T-Pager exposes Small/Medium/Large font presets. Reboot to apply. */ +/* UI-size preset. Large-screen boards retain their 0..2 percentage mapping; + * the T-Pager exposes four 0..3 semantic font presets. Reboot to apply. */ uint8_t touchPrefsGetUiScale(); bool touchPrefsSetUiScale(uint8_t scale); diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 12fc6490..e5506f5b 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -603,6 +603,19 @@ static inline const lv_font_t* uiChromeFont() { #endif } +// Jumbo is deliberately an Extra Large UI with only conversation text taken +// one step further. Keeping this role separate avoids enlarging status chrome, +// settings, timestamps, sender labels, and the composer on the Pager's short +// display. Compact-chat rows use the same role because the message and metadata +// share a single LVGL label there. +static inline const lv_font_t* chatMessageFont() { +#if defined(TLORA_PAGER) + return touchPrefsGetUiScale() == 3 ? &g_font_14 : &g_font_12; +#else + return &g_font_12; +#endif +} + static void initTouchFontFallbacks() { #if defined(TLORA_PAGER) // The Pager is wide but only 222 px tall. Grow the semantic text roles while @@ -616,6 +629,7 @@ static void initTouchFontFallbacks() { g_font_16 = lv_font_montserrat_20; break; case 2: + case 3: // Jumbo keeps Extra Large chrome; chat message text is bumped separately. g_font_12 = lv_font_montserrat_18; g_font_14 = lv_font_montserrat_20; g_font_16 = lv_font_montserrat_24; @@ -658,7 +672,8 @@ static void initTouchFontFallbacks() { #if defined(TLORA_PAGER) switch (touchPrefsGetUiScale()) { case 1: extras[0] = &extras_16; extras[1] = &extras_20; extras[2] = &extras_20; break; - case 2: extras[0] = &extras_20; extras[1] = &extras_20; extras[2] = &extras_24; break; + case 2: + case 3: extras[0] = &extras_20; extras[1] = &extras_20; extras[2] = &extras_24; break; default: break; } #endif @@ -1590,14 +1605,12 @@ static inline lv_coord_t chatComposerTaW() { const lv_coord_t chip = chatComposerChipSz(); return chatScreenW() - (2 * chip + 12) - chatComposerSendSz() - 14; } -// The status bar is DOUBLE height in a chat (thread name on the lower row + a centred -// cog). chatBarH() is that full visual height (used by the channel/blocked sheets). The -// conversation itself, though, starts just under the SOLID top row (STATUSBAR_H): the -// bar's lower row is a translucent glass strip (see updateGlobalStatusBar) that the -// bubbles scroll UNDER — p.msgs carries a top inset == that row so the newest content -// still rests below the bar. -#if CAP_ROUND_CORNERS -static inline lv_coord_t chatBarH() { return STATUSBAR_H; } // fixed two-row bar, no doubling +// Most boards use a DOUBLE-height status bar in a chat (thread name on the lower +// row + a centred cog). The round panel already has two physical rows, while the +// short Pager keeps its back/cog/title in the regular single row. chatBarH() is +// the full visual height used by channel/blocked sheets. +#if CAP_ROUND_CORNERS || defined(TLORA_PAGER) +static inline lv_coord_t chatBarH() { return STATUSBAR_H; } #else static inline lv_coord_t chatBarH() { return (lv_coord_t)(STATUSBAR_H * 2); } #endif @@ -2750,8 +2763,8 @@ static void styleButton(lv_obj_t* obj) { } // "X" close affordance for popup cards. A bare 16-px glyph with an -// invisible 32×32 tap target so it reads as just a symbol but is forgiving -// to hit on a 240-px touch screen. Sits flush inside the card's top-right +// Compact 24×24 visual target with a 32×32 extended hit area, so it reads as +// just a symbol but remains forgiving to hit. Sits inside the card's top-right // corner — no border / bg, so it doesn't compete visually with the card's // own buttons. // IMPORTANT: each caller is responsible for keeping the top-right ~32×32 @@ -2768,16 +2781,17 @@ static inline void tanCloseRed(lv_obj_t* lbl) { static lv_obj_t* addCloseXBadge(lv_obj_t* card, lv_event_cb_t cb, void* user_data = nullptr) { lv_obj_t* x = lv_obj_create(card); lv_obj_remove_style_all(x); - lv_obj_set_size(x, 32, 32); - // Flush to top-right of the card. No outward offset — keeps the badge - // entirely on top of the card so it can't clip behind the modal backdrop. - lv_obj_align(x, LV_ALIGN_TOP_RIGHT, 0, 0); + lv_obj_set_size(x, 24, 24); + // Keep the visible focus tint tight around the centred glyph. ext_click_area + // restores the previous forgiving 32-px touch target without painting it. + lv_obj_align(x, LV_ALIGN_TOP_RIGHT, -2, 2); + lv_obj_set_ext_click_area(x, 4); // No fill / border — bare glyph. Pressed state nudges a faint dim so // there's *some* visual feedback on tap. lv_obj_set_style_bg_opa(x, LV_OPA_TRANSP, LV_PART_MAIN); lv_obj_set_style_bg_color(x, lv_color_hex(0xFFFFFF), LV_PART_MAIN | LV_STATE_PRESSED); lv_obj_set_style_bg_opa(x, LV_OPA_20, LV_PART_MAIN | LV_STATE_PRESSED); - lv_obj_set_style_radius(x, 16, LV_PART_MAIN); + lv_obj_set_style_radius(x, 12, LV_PART_MAIN); lv_obj_set_style_border_width(x, 0, LV_PART_MAIN); lv_obj_set_style_pad_all(x, 0, LV_PART_MAIN); lv_obj_add_flag(x, LV_OBJ_FLAG_CLICKABLE); @@ -2798,11 +2812,7 @@ static lv_obj_t* addCloseXBadge(lv_obj_t* card, lv_event_cb_t cb, void* user_dat #else lv_obj_set_style_text_color(lbl, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); #endif - // Anchor the glyph itself to the TOP-RIGHT of the (32×32) tap area — - // centering it made the X look like it was floating in the middle of - // nothing. The 32×32 hit zone still extends down/left for an easy tap, - // but visually the glyph occupies the corner of the popup card. - lv_obj_align(lbl, LV_ALIGN_TOP_RIGHT, -6, 4); + lv_obj_center(lbl); return x; } @@ -7772,13 +7782,16 @@ static void openQuickReplyPicker(LvChatPanel* p) { const int col_gap = 0; #elif defined(TLORA_PAGER) const int card_w = 360; - const int btn_h = 32; - const int pad = 8; - const int title_h = 26; - const int hint_h = 22; - const int row_gap = 4; + // Six replies fit in three compact rows. Keep the picker entirely inside + // the 200-px viewport instead of relying on a height clamp whose absolutely + // positioned footer was only reachable by scrolling past the card edge. + const int btn_h = 30; + const int pad = 6; + const int title_h = 24; + const int hint_h = 18; + const int row_gap = 3; const int cols = 2; - const int col_gap = 8; + const int col_gap = 6; #else const int card_w = 220; const int btn_h = 32; // 34→32: 6 macro rows have to fit in the @@ -7793,6 +7806,9 @@ static void openQuickReplyPicker(LvChatPanel* p) { const int rows = (TOUCH_QUICK_REPLY_COUNT + cols - 1) / cols; // ceil, in case the macro count ever changes const int gps_row_h = btn_h + row_gap; // GPS-position row: always full-width, sits above the macro grid int card_h = title_h + gps_row_h + rows * (btn_h + row_gap) + hint_h + pad; +#if defined(TLORA_PAGER) + card_h += pad; // both top and bottom content padding are inside the fixed-height card +#endif if (card_h > sh - STATUSBAR_H - 8) card_h = sh - STATUSBAR_H - 8; // never taller than the visible area lv_obj_t* card = lv_obj_create(s_qr_sheet); lv_obj_remove_style_all(card); @@ -7815,7 +7831,11 @@ static void openQuickReplyPicker(LvChatPanel* p) { lv_obj_t* title = lv_label_create(card); lv_label_set_text(title, TR("Quick reply")); lv_obj_set_style_text_color(title, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); +#if defined(TLORA_PAGER) + lv_obj_set_style_text_font(title, uiChromeFont(), LV_PART_MAIN); +#else lv_obj_set_style_text_font(title, &g_font_14, LV_PART_MAIN); +#endif lv_obj_set_pos(title, 0, 0); #if defined(ESP32) @@ -7835,7 +7855,13 @@ static void openQuickReplyPicker(LvChatPanel* p) { lv_label_set_text(lbl, gbuf); lv_label_set_long_mode(lbl, LV_LABEL_LONG_DOT); lv_obj_set_width(lbl, card_w - 2 * pad - 16); - lv_obj_set_style_text_font(lbl, &g_font_12, LV_PART_MAIN); + lv_obj_set_style_text_font(lbl, +#if defined(TLORA_PAGER) + uiChromeFont(), +#else + &g_font_12, +#endif + LV_PART_MAIN); lv_obj_set_style_text_color(lbl, lv_color_hex(fix ? COLOR_TEXT : COLOR_SUB), LV_PART_MAIN); lv_obj_align(lbl, LV_ALIGN_LEFT_MID, 8, 0); } @@ -7854,7 +7880,13 @@ static void openQuickReplyPicker(LvChatPanel* p) { lv_label_set_text(lbl, buf); lv_label_set_long_mode(lbl, LV_LABEL_LONG_DOT); lv_obj_set_width(lbl, col_w - 16); - lv_obj_set_style_text_font(lbl, &g_font_12, LV_PART_MAIN); + lv_obj_set_style_text_font(lbl, +#if defined(TLORA_PAGER) + uiChromeFont(), +#else + &g_font_12, +#endif + LV_PART_MAIN); lv_obj_set_style_text_color(lbl, lv_color_hex(n > 0 ? COLOR_TEXT : COLOR_SUB), LV_PART_MAIN); lv_obj_align(lbl, LV_ALIGN_LEFT_MID, 8, 0); } @@ -7863,7 +7895,13 @@ static void openQuickReplyPicker(LvChatPanel* p) { lv_obj_t* hint = lv_label_create(card); lv_label_set_text(hint, TR("Edit in Settings \xe2\x86\x92 Quick replies")); lv_obj_set_style_text_color(hint, lv_color_hex(COLOR_SUB), LV_PART_MAIN); +#if defined(TLORA_PAGER) + lv_obj_set_style_text_font(hint, &lv_font_montserrat_12, LV_PART_MAIN); + lv_label_set_long_mode(hint, LV_LABEL_LONG_DOT); + lv_obj_set_width(hint, card_w - 2 * pad); +#else lv_obj_set_style_text_font(hint, &g_font_12, LV_PART_MAIN); +#endif lv_obj_set_pos(hint, 0, y + 2); } @@ -12218,7 +12256,7 @@ static void buildDeviceSettings(int sec) { y += settingsRowLabel(body, y, 0, TR("UI size (restart to apply)"), COLOR_SUB, &g_font_12, 0) + 2; lv_obj_t* dd = lv_dropdown_create(body); #if defined(TLORA_PAGER) - lv_dropdown_set_options(dd, TR("Small\nMedium\nLarge")); + lv_dropdown_set_options(dd, "Default\nLarge\nExtra Large\nJumbo"); #else lv_dropdown_set_options(dd, TR("Normal (100%)\nLarge (150%)\nHuge (200%)")); #endif @@ -22818,7 +22856,7 @@ static void makeHome(lv_obj_t* tab) { // RSTRIP is the strip the left-hand content (status text + chart + info) must stay clear of. #if defined(TLORA_PAGER) const uint8_t pager_size = touchPrefsGetUiScale(); - const int BTNW = pager_size == 2 ? 136 : pager_size == 1 ? 120 : 100; + const int BTNW = pager_size >= 2 ? 136 : pager_size == 1 ? 120 : 100; const int home_line_h = lv_font_get_line_height(&g_font_14); const int home_state_y = pager_size ? 2 : 4; const int home_unread_y = pager_size ? home_state_y + home_line_h + 2 : 22; @@ -29160,16 +29198,20 @@ static void makeChatDetail(LvChatPanel& p) { lv_obj_set_style_border_width(p.msgs, 0, LV_PART_MAIN); lv_obj_set_style_radius(p.msgs, 0, LV_PART_MAIN); lv_obj_set_style_pad_all(p.msgs, 6, LV_PART_MAIN); - // The status bar's glass lower row floats over the TOP of the list — inset the top by - // that row height so the first bubble rests just below the bar and older ones scroll - // UNDER it (mirrors the composer at the bottom). + // The status bar's glass lower row floats over the TOP of the list on boards + // with a two-row chat header. Pager keeps the chat header in one regular row, + // so retaining that old row-sized inset only wastes message space. +#if defined(TLORA_PAGER) + lv_obj_set_style_pad_top(p.msgs, 6, LV_PART_MAIN); +#else lv_obj_set_style_pad_top(p.msgs, STATUSBAR_H + 6, LV_PART_MAIN); +#endif // The composer floats over the list's lower edge (transparent row), so reserve a // bottom inset == the composer height: the newest bubble rests just above it and // older ones scroll UNDER it. Kept in sync with s_comp_h by chatComposerAutoGrow. lv_obj_set_style_pad_bottom(p.msgs, s_comp_h + 6, LV_PART_MAIN); lv_obj_set_style_text_color(p.msgs, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); - lv_obj_set_style_text_font(p.msgs, &g_font_12, LV_PART_MAIN); + lv_obj_set_style_text_font(p.msgs, chatMessageFont(), LV_PART_MAIN); lv_obj_set_scrollbar_mode(p.msgs, LV_SCROLLBAR_MODE_AUTO); lv_obj_set_scroll_dir(p.msgs, LV_DIR_VER); lv_obj_set_layout(p.msgs, 0); // no flex/grid — bubbles use absolute Y; spacer sets scroll height @@ -31375,7 +31417,7 @@ static void chatParseMessageDisplay(const UITask::UIMessage& m, bool channel_mod } } copyUtf8ReplacingMissingGlyphs(&g_font_12, d.san_sender, sizeof(d.san_sender), d.show_sender); - copyUtf8ReplacingMissingGlyphs(&g_font_12, d.san_text, sizeof(d.san_text), d.show_text); + copyUtf8ReplacingMissingGlyphs(chatMessageFont(), d.san_text, sizeof(d.san_text), d.show_text); } // ---- Chat virt serial diagnostics ------------------------------------------- @@ -31547,11 +31589,12 @@ static lv_coord_t chatMeasureBubbleHeight(const UITask::UIMessage& m, bool chann if (show_sender || meta_buf[0]) inner_y += lv_font_get_line_height(&g_font_12); + const lv_font_t* msg_font = chatMessageFont(); lv_point_t txt_size; - lv_txt_get_size(&txt_size, d.san_text, &g_font_12, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE); + lv_txt_get_size(&txt_size, d.san_text, msg_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE); const lv_coord_t txt_w_used = (txt_size.x <= inner_max_w) ? txt_size.x : inner_max_w; lv_point_t wrapped_size; - lv_txt_get_size(&wrapped_size, d.san_text, &g_font_12, 0, 0, + lv_txt_get_size(&wrapped_size, d.san_text, msg_font, 0, 0, txt_w_used > 0 ? txt_w_used : LV_COORD_MAX, LV_TEXT_FLAG_NONE); return kChatBubblePadV * 2 + inner_y + wrapped_size.y; @@ -31664,7 +31707,7 @@ static lv_coord_t chatMeasureCompactRowHeight(const UITask::UIMessage& m, LvChat ? s_chat_virt.content_w - kPadH * 2 : s_chat_virt.content_w; lv_point_t wrapped; - lv_txt_get_size(&wrapped, line, &g_font_12, 0, 0, + lv_txt_get_size(&wrapped, line, chatMessageFont(), 0, 0, inner_w > 0 ? inner_w : LV_COORD_MAX, LV_TEXT_FLAG_NONE); return wrapped.y + kPadV * 2; } @@ -32264,8 +32307,9 @@ static lv_coord_t chatVirtCreateBubble(LvChatPanel* p, int logical_i, int ring_i lv_obj_set_size(bubble, LV_SIZE_CONTENT, LV_SIZE_CONTENT); const lv_coord_t kInnerMaxW = kBubbleMaxW - 2 * kChatBubblePadH; + const lv_font_t* msg_font = chatMessageFont(); lv_point_t txt_size; - lv_txt_get_size(&txt_size, d.san_text, &g_font_12, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE); + lv_txt_get_size(&txt_size, d.san_text, msg_font, 0, 0, LV_COORD_MAX, LV_TEXT_FLAG_NONE); const lv_coord_t txt_w_used = (txt_size.x <= kInnerMaxW) ? txt_size.x : kInnerMaxW; char meta_buf[48]; @@ -32327,7 +32371,7 @@ static lv_coord_t chatVirtCreateBubble(LvChatPanel* p, int logical_i, int ring_i } lv_obj_t* tlbl = lv_label_create(bubble); - lv_obj_set_style_text_font(tlbl, &g_font_12, LV_PART_MAIN); + lv_obj_set_style_text_font(tlbl, msg_font, LV_PART_MAIN); lv_obj_set_style_text_color(tlbl, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); lv_label_set_text(tlbl, d.san_text); // Clickable URLs: tint any link blue (recolor tags are zero-width, so wrapping/height @@ -32387,7 +32431,7 @@ static lv_coord_t chatVirtCreateCompactRow(LvChatPanel* p, int logical_i, int ri lv_obj_t* row = lv_label_create(p->msgs); lv_label_set_recolor(row, true); lv_obj_add_flag(row, LV_OBJ_FLAG_FLOATING); - lv_obj_set_style_text_font(row, &g_font_12, LV_PART_MAIN); + lv_obj_set_style_text_font(row, chatMessageFont(), LV_PART_MAIN); lv_obj_set_style_text_color(row, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); lv_label_set_long_mode(row, LV_LABEL_LONG_WRAP); lv_obj_set_width(row, s_chat_virt.content_w); @@ -40122,8 +40166,13 @@ static void buildGlobalStatusBar() { g_statusbar.chat_back = lv_label_create(g_statusbar.root); lv_label_set_text(g_statusbar.chat_back, LV_SYMBOL_LEFT); lv_obj_set_style_text_color(g_statusbar.chat_back, lv_color_hex(COLOR_ACCENT), LV_PART_MAIN); +#if defined(TLORA_PAGER) + lv_obj_set_style_text_font(g_statusbar.chat_back, uiChromeFont(), LV_PART_MAIN); + lv_obj_align(g_statusbar.chat_back, LV_ALIGN_LEFT_MID, 6, 0); +#else lv_obj_set_style_text_font(g_statusbar.chat_back, &g_font_16, LV_PART_MAIN); lv_obj_align(g_statusbar.chat_back, LV_ALIGN_LEFT_MID, 12, 0); // breathing room from the edge +#endif lv_obj_add_flag(g_statusbar.chat_back, LV_OBJ_FLAG_HIDDEN); // Channel-settings gear — RIGHT of the back chevron, shown only inside a chat @@ -40132,8 +40181,13 @@ static void buildGlobalStatusBar() { g_statusbar.chan_gear = lv_label_create(g_statusbar.root); lv_label_set_text(g_statusbar.chan_gear, LV_SYMBOL_SETTINGS); lv_obj_set_style_text_color(g_statusbar.chan_gear, lv_color_hex(COLOR_TEXT), LV_PART_MAIN); +#if defined(TLORA_PAGER) + lv_obj_set_style_text_font(g_statusbar.chan_gear, uiChromeFont(), LV_PART_MAIN); + lv_obj_align(g_statusbar.chan_gear, LV_ALIGN_LEFT_MID, 30, 0); +#else lv_obj_set_style_text_font(g_statusbar.chan_gear, &g_font_16, LV_PART_MAIN); lv_obj_align(g_statusbar.chan_gear, LV_ALIGN_LEFT_MID, 44, 0); // gap after the back chevron +#endif lv_obj_add_flag(g_statusbar.chan_gear, LV_OBJ_FLAG_CLICKABLE); lv_obj_set_ext_click_area(g_statusbar.chan_gear, 10); lv_obj_add_flag(g_statusbar.chan_gear, LV_OBJ_FLAG_HIDDEN); @@ -40436,8 +40490,8 @@ static void updateGlobalStatusBar() { // ---- Double-height bar driver (edge-triggered) ---- // The bar goes 2× tall for (a) settings detail pages, (b) the chat/channel OVERVIEW // (lower row = [+ ✓ QR] actions), and (c) an OPEN chat (lower row = thread name, cog - // centred across both rows). Pager's compact overview actions share the regular top - // row, so its overview stays single-height. + // centred across both rows). Pager's compact overview and open-chat controls share + // the regular top row, so both states stay single-height. // An open app/tool page (the reader, RF Monitor, …) takes over the bar even when a // chat is still open underneath it, so suppress chat-mode chrome (the cog + back // chevron + centred title) then — otherwise they sit over the page's "‹ title" and @@ -40446,7 +40500,7 @@ static void updateGlobalStatusBar() { const bool inbox_overview = (getActiveTab() == CHAT_INBOX_TAB_INDEX) && !chat_open && (s_settings_open_cat < 0) && !s_apppage_title; { #if defined(TLORA_PAGER) - const bool want_tall = (s_settings_open_cat >= 0) || (s_apppage_title && !s_apppage_slim) || chat_open; + const bool want_tall = (s_settings_open_cat >= 0) || (s_apppage_title && !s_apppage_slim); #else const bool want_tall = (s_settings_open_cat >= 0) || (s_apppage_title && !s_apppage_slim) || inbox_overview || chat_open; #endif @@ -40539,9 +40593,21 @@ static void updateGlobalStatusBar() { } #else if (in_chan_chat) { +#if defined(TLORA_PAGER) + // Back + gear occupy the first 48 px; cap the title before the clock so + // the entire open-chat header shares the overview/status baseline. + lv_obj_align(g_statusbar.left_label, LV_ALIGN_LEFT_MID, 54, 0); + lv_obj_set_width(g_statusbar.left_label, 140); + lv_label_set_long_mode(g_statusbar.left_label, LV_LABEL_LONG_DOT); +#else lv_obj_align(g_statusbar.left_label, LV_ALIGN_CENTER, 0, 0); +#endif } else { lv_obj_align(g_statusbar.left_label, LV_ALIGN_LEFT_MID, 6, 0); +#if defined(TLORA_PAGER) + lv_obj_set_width(g_statusbar.left_label, 200); + lv_label_set_long_mode(g_statusbar.left_label, LV_LABEL_LONG_DOT); +#endif } #endif @@ -40560,7 +40626,7 @@ static void updateGlobalStatusBar() { #endif if (!home_zone && s_left_home_cfg) { #if defined(TLORA_PAGER) - lv_obj_set_width(g_statusbar.left_label, 200); + lv_obj_set_width(g_statusbar.left_label, in_chan_chat ? 140 : 200); lv_label_set_long_mode(g_statusbar.left_label, LV_LABEL_LONG_DOT); #else lv_obj_set_width(g_statusbar.left_label, LV_SIZE_CONTENT);