From 423ddcb2878a37421d53fc779a6b6607afc73a3d Mon Sep 17 00:00:00 2001 From: ZhouKe <9482145@qq.com> Date: Tue, 18 Mar 2025 00:47:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9C=A8LCD=E9=9D=A2=E6=9D=BF=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=BE=AE=E4=BF=A1=E8=81=8A=E5=A4=A9=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E3=80=82=20(#356)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 在LCD面板使用微信聊天样式。 * 调整换行 --- main/Kconfig.projbuild | 6 + .../compact_wifi_board_lcd.cc | 4 + main/display/lcd_display.cc | 256 ++++++++++++++++++ main/display/lcd_display.h | 3 + 4 files changed, 269 insertions(+) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 54dec304..c471304d 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -212,6 +212,12 @@ choice DISPLAY_ESP32S3_KORVO2_V3 bool "ILI9341, 分辨率240*320" endchoice +config USE_WECHAT_MESSAGE_STYLE + bool "使用微信聊天界面风格" + default n + help + 使用微信聊天界面风格 + config USE_AUDIO_PROCESSOR bool "启用音频降噪、增益处理" default y diff --git a/main/boards/bread-compact-wifi-lcd/compact_wifi_board_lcd.cc b/main/boards/bread-compact-wifi-lcd/compact_wifi_board_lcd.cc index 3110c6e8..2d13d80c 100644 --- a/main/boards/bread-compact-wifi-lcd/compact_wifi_board_lcd.cc +++ b/main/boards/bread-compact-wifi-lcd/compact_wifi_board_lcd.cc @@ -127,7 +127,11 @@ private: { .text_font = &font_puhui_16_4, .icon_font = &font_awesome_16_4, +#if CONFIG_USE_WECHAT_MESSAGE_STYLE + .emoji_font = font_emoji_32_init(), +#else .emoji_font = DISPLAY_HEIGHT >= 240 ? font_emoji_64_init() : font_emoji_32_init(), +#endif }); } diff --git a/main/display/lcd_display.cc b/main/display/lcd_display.cc index 9cb4dba7..ddf90526 100644 --- a/main/display/lcd_display.cc +++ b/main/display/lcd_display.cc @@ -6,6 +6,7 @@ #include #include #include "assets/lang_config.h" +#include #include "board.h" @@ -176,6 +177,260 @@ void LcdDisplay::Unlock() { lvgl_port_unlock(); } +#if CONFIG_USE_WECHAT_MESSAGE_STYLE +void LcdDisplay::SetupUI() { + DisplayLockGuard lock(this); + + auto screen = lv_screen_active(); + lv_obj_set_style_text_font(screen, fonts_.text_font, 0); + lv_obj_set_style_text_color(screen, lv_color_black(), 0); + + /* Container */ + container_ = lv_obj_create(screen); + lv_obj_set_size(container_, LV_HOR_RES, LV_VER_RES); + lv_obj_set_flex_flow(container_, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_all(container_, 0, 0); + lv_obj_set_style_border_width(container_, 0, 0); + lv_obj_set_style_pad_row(container_, 0, 0); + + /* Status bar */ + status_bar_ = lv_obj_create(container_); + lv_obj_set_size(status_bar_, LV_HOR_RES, fonts_.emoji_font->line_height); + lv_obj_set_style_radius(status_bar_, 0, 0); + + /* Content - Chat area */ + content_ = lv_obj_create(container_); + lv_obj_set_style_radius(content_, 0, 0); + lv_obj_set_width(content_, LV_HOR_RES); + lv_obj_set_flex_grow(content_, 1); + lv_obj_set_style_pad_all(content_, 5, 0); + lv_obj_set_style_bg_color(content_, lv_color_hex(0xE0E0E0), 0); // Light gray background like WeChat + + // Enable scrolling for chat content + lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_scroll_dir(content_, LV_DIR_VER); + + // Create a flex container for chat messages + lv_obj_set_flex_flow(content_, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START); + lv_obj_set_style_pad_row(content_, 10, 0); // Space between messages + + // We'll create chat messages dynamically in SetChatMessage + chat_message_label_ = nullptr; + + /* Status bar */ + lv_obj_set_flex_flow(status_bar_, LV_FLEX_FLOW_ROW); + lv_obj_set_style_pad_all(status_bar_, 0, 0); + lv_obj_set_style_border_width(status_bar_, 0, 0); + lv_obj_set_style_pad_column(status_bar_, 0, 0); + lv_obj_set_style_pad_left(status_bar_, 2, 0); + lv_obj_set_style_pad_right(status_bar_, 2, 0); + lv_obj_set_scrollbar_mode(status_bar_, LV_SCROLLBAR_MODE_OFF); + + network_label_ = lv_label_create(status_bar_); + lv_label_set_text(network_label_, ""); + lv_obj_set_style_text_font(network_label_, fonts_.icon_font, 0); + + notification_label_ = lv_label_create(status_bar_); + lv_obj_set_flex_grow(notification_label_, 1); + lv_obj_set_style_text_align(notification_label_, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_text(notification_label_, ""); + lv_obj_add_flag(notification_label_, LV_OBJ_FLAG_HIDDEN); + + status_label_ = lv_label_create(status_bar_); + lv_obj_set_flex_grow(status_label_, 1); + lv_label_set_long_mode(status_label_, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_obj_set_style_text_align(status_label_, LV_TEXT_ALIGN_CENTER, 0); + lv_label_set_text(status_label_, Lang::Strings::INITIALIZING); + + mute_label_ = lv_label_create(status_bar_); + lv_label_set_text(mute_label_, ""); + lv_obj_set_style_text_font(mute_label_, fonts_.icon_font, 0); + + battery_label_ = lv_label_create(status_bar_); + lv_label_set_text(battery_label_, ""); + lv_obj_set_style_text_font(battery_label_, fonts_.icon_font, 0); + + // 创建emotion_label_在状态栏最右侧 + emotion_label_ = lv_label_create(status_bar_); + lv_obj_set_style_text_font(emotion_label_, &font_awesome_30_4, 0); + lv_label_set_text(emotion_label_, FONT_AWESOME_AI_CHIP); + lv_obj_set_style_margin_left(emotion_label_, 5, 0); // 添加左边距,与前面的元素分隔 + + low_battery_popup_ = lv_obj_create(screen); + lv_obj_set_scrollbar_mode(low_battery_popup_, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_size(low_battery_popup_, LV_HOR_RES * 0.9, fonts_.text_font->line_height * 2); + lv_obj_align(low_battery_popup_, LV_ALIGN_BOTTOM_MID, 0, 0); + lv_obj_set_style_bg_color(low_battery_popup_, lv_color_black(), 0); + lv_obj_set_style_radius(low_battery_popup_, 10, 0); + lv_obj_t* low_battery_label = lv_label_create(low_battery_popup_); + lv_label_set_text(low_battery_label, Lang::Strings::BATTERY_NEED_CHARGE); + lv_obj_set_style_text_color(low_battery_label, lv_color_white(), 0); + lv_obj_center(low_battery_label); + lv_obj_add_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN); +} + +#define MAX_MESSAGES 50 +void LcdDisplay::SetChatMessage(const char* role, const char* content) { + DisplayLockGuard lock(this); + if (content_ == nullptr) { + return; + } + + //避免出现空的消息框 + if(strlen(content) == 0) return; + + // Create a message bubble + lv_obj_t* msg_bubble = lv_obj_create(content_); + lv_obj_set_style_radius(msg_bubble, 8, 0); + lv_obj_set_scrollbar_mode(msg_bubble, LV_SCROLLBAR_MODE_OFF); + lv_obj_set_style_border_width(msg_bubble, 1, 0); + lv_obj_set_style_border_color(msg_bubble, lv_color_hex(0xE0E0E0), 0); + lv_obj_set_style_pad_all(msg_bubble, 8, 0); + + // Create the message text + lv_obj_t* msg_text = lv_label_create(msg_bubble); + lv_label_set_text(msg_text, content); + + // 计算文本实际宽度 + lv_coord_t text_width = lv_txt_get_width(content, strlen(content), fonts_.text_font, 0); + + // 计算气泡宽度 + lv_coord_t max_width = LV_HOR_RES * 85 / 100 - 16; // 屏幕宽度的85% + lv_coord_t min_width = 20; + lv_coord_t bubble_width; + + // 确保文本宽度不小于最小宽度 + if (text_width < min_width) { + text_width = min_width; + } + + // 如果文本宽度小于最大宽度,使用文本宽度 + if (text_width < max_width) { + bubble_width = text_width; + } else { + bubble_width = max_width; + } + + // 设置消息文本的宽度 + lv_obj_set_width(msg_text, bubble_width); // 减去padding + lv_label_set_long_mode(msg_text, LV_LABEL_LONG_WRAP); + lv_obj_set_style_text_font(msg_text, fonts_.text_font, 0); + + // 设置气泡宽度 + lv_obj_set_width(msg_bubble, bubble_width); + lv_obj_set_height(msg_bubble, LV_SIZE_CONTENT); + + // Set alignment and style based on message role + if (strcmp(role, "user") == 0) { + // User messages are right-aligned with green background + lv_obj_set_style_bg_color(msg_bubble, lv_color_hex(0x95EC69), 0); // WeChat green + // Set text color for contrast + lv_obj_set_style_text_color(msg_text, lv_color_black(), 0); + + // Set appropriate width for content + lv_obj_set_width(msg_bubble, LV_SIZE_CONTENT); + lv_obj_set_height(msg_bubble, LV_SIZE_CONTENT); + + // Add some margin + lv_obj_set_style_margin_right(msg_bubble, 10, 0); + + // Don't grow + lv_obj_set_style_flex_grow(msg_bubble, 0, 0); + } else if (strcmp(role, "assistant") == 0) { + // Assistant messages are left-aligned with white background + lv_obj_set_style_bg_color(msg_bubble, lv_color_white(), 0); + // Set text color for contrast + lv_obj_set_style_text_color(msg_text, lv_color_black(), 0); + + // Set appropriate width for content + lv_obj_set_width(msg_bubble, LV_SIZE_CONTENT); + lv_obj_set_height(msg_bubble, LV_SIZE_CONTENT); + + // Add some margin + lv_obj_set_style_margin_left(msg_bubble, 0, 0); + + // Don't grow + lv_obj_set_style_flex_grow(msg_bubble, 0, 0); + } else if (strcmp(role, "system") == 0) { + // System messages are center-aligned with light gray background + lv_obj_set_style_bg_color(msg_bubble, lv_color_hex(0xE0E0E0), 0); // 浅灰色背景 + // Set text color for contrast + lv_obj_set_style_text_color(msg_text, lv_color_hex(0x666666), 0); // 深灰色文字 + + // Set appropriate width for content + lv_obj_set_width(msg_bubble, LV_SIZE_CONTENT); + lv_obj_set_height(msg_bubble, LV_SIZE_CONTENT); + + // Don't grow + lv_obj_set_style_flex_grow(msg_bubble, 0, 0); + } + + // Create a full-width container for user messages to ensure right alignment + if (strcmp(role, "user") == 0) { + // Create a full-width container + lv_obj_t* container = lv_obj_create(content_); + lv_obj_set_width(container, LV_HOR_RES); + lv_obj_set_height(container, LV_SIZE_CONTENT); + + // Make container transparent and borderless + lv_obj_set_style_bg_opa(container, LV_OPA_TRANSP, 0); + lv_obj_set_style_border_width(container, 0, 0); + lv_obj_set_style_pad_all(container, 0, 0); + + // Move the message bubble into this container + lv_obj_set_parent(msg_bubble, container); + + // Right align the bubble in the container + lv_obj_align(msg_bubble, LV_ALIGN_RIGHT_MID, -10, 0); + + // Auto-scroll to this container + lv_obj_scroll_to_view_recursive(container, LV_ANIM_ON); + } else if (strcmp(role, "system") == 0) { + // 为系统消息创建全宽容器以确保居中对齐 + lv_obj_t* container = lv_obj_create(content_); + lv_obj_set_width(container, LV_HOR_RES); + lv_obj_set_height(container, LV_SIZE_CONTENT); + + // 使容器透明且无边框 + lv_obj_set_style_bg_opa(container, LV_OPA_TRANSP, 0); + lv_obj_set_style_border_width(container, 0, 0); + lv_obj_set_style_pad_all(container, 0, 0); + + // 将消息气泡移入此容器 + lv_obj_set_parent(msg_bubble, container); + + // 将气泡居中对齐在容器中 + lv_obj_align(msg_bubble, LV_ALIGN_CENTER, 0, 0); + + // 自动滚动底部 + lv_obj_scroll_to_view_recursive(container, LV_ANIM_ON); + } else { + // For assistant messages + // Left align assistant messages + lv_obj_align(msg_bubble, LV_ALIGN_LEFT_MID, 0, 0); + + // Auto-scroll to the message bubble + lv_obj_scroll_to_view_recursive(msg_bubble, LV_ANIM_ON); + } + + // Store reference to the latest message label + chat_message_label_ = msg_text; + + // 检查消息数量是否超过限制 + uint32_t msg_count = lv_obj_get_child_cnt(content_); + while (msg_count >= MAX_MESSAGES) { + // 删除最早的消息(第一个子节点) + lv_obj_t* oldest_msg = lv_obj_get_child(content_, 0); + if (oldest_msg != nullptr) { + lv_obj_del(oldest_msg); + msg_count--; + }else{ + break; + } + } +} +#else void LcdDisplay::SetupUI() { DisplayLockGuard lock(this); @@ -259,6 +514,7 @@ void LcdDisplay::SetupUI() { lv_obj_center(low_battery_label); lv_obj_add_flag(low_battery_popup_, LV_OBJ_FLAG_HIDDEN); } +#endif void LcdDisplay::SetEmotion(const char* emotion) { struct Emotion { diff --git a/main/display/lcd_display.h b/main/display/lcd_display.h index e85c1a1a..bda375c6 100644 --- a/main/display/lcd_display.h +++ b/main/display/lcd_display.h @@ -35,6 +35,9 @@ public: ~LcdDisplay(); virtual void SetEmotion(const char* emotion) override; virtual void SetIcon(const char* icon) override; +#if CONFIG_USE_WECHAT_MESSAGE_STYLE + virtual void SetChatMessage(const char* role, const char* content) override; +#endif }; // RGB LCD显示器