From b6c61fe390dcc66d73f61d797c7ca499e02106d1 Mon Sep 17 00:00:00 2001 From: Xiaoxia Date: Sun, 1 Feb 2026 01:04:24 +0800 Subject: [PATCH] Update project version to 2.2.2, Noto fonts and emoji support. (#1720) --- CMakeLists.txt | 2 +- main/CMakeLists.txt | 64 +++++++++++------------ main/application.cc | 3 +- main/display/display.cc | 4 ++ main/display/display.h | 1 + main/display/lcd_display.cc | 59 ++++++++++++++++----- main/display/lcd_display.h | 3 +- main/display/lvgl_display/gif/lvgl_gif.cc | 50 ++++++++++++++++-- main/display/lvgl_display/gif/lvgl_gif.h | 16 ++++++ main/idf_component.yml | 2 +- scripts/build_default_assets.py | 21 +++++--- 11 files changed, 168 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 90c5c94c..a32048cb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,5 +9,5 @@ include($ENV{IDF_PATH}/tools/cmake/project.cmake) # "Trim" the build. Include the minimal set of components, main, and anything it depends on. idf_build_set_property(MINIMAL_BUILD ON) -set(PROJECT_VER "2.2.1") +set(PROJECT_VER "2.2.2") project(xiaozhi) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 565bdd55..d03bbae7 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -104,28 +104,28 @@ elseif(CONFIG_BOARD_TYPE_BREAD_COMPACT_ESP32_LCD) set(BUILTIN_ICON_FONT font_awesome_14_1) elseif(CONFIG_BOARD_TYPE_DF_K10) set(BOARD_TYPE "df-k10") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_DF_S3_AI_CAM) set(BOARD_TYPE "df-s3-ai-cam") elseif(CONFIG_BOARD_TYPE_ESP_BOX_3) set(BOARD_TYPE "esp-box-3") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) set(EMOTE_RESOLUTION "320_240") elseif(CONFIG_BOARD_TYPE_ESP_BOX) set(BOARD_TYPE "esp-box") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) set(EMOTE_RESOLUTION "320_240") elseif(CONFIG_BOARD_TYPE_ESP_BOX_LITE) set(BOARD_TYPE "esp-box-lite") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_KEVIN_BOX_2) set(BOARD_TYPE "kevin-box-2") set(BUILTIN_TEXT_FONT font_puhui_basic_14_1) @@ -134,14 +134,14 @@ elseif(CONFIG_BOARD_TYPE_KEVIN_C3) set(BOARD_TYPE "kevin-c3") elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V3_DEV) set(BOARD_TYPE "kevin-sp-v3-dev") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_KEVIN_SP_V4_DEV) set(BOARD_TYPE "kevin-sp-v4-dev") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_KEVIN_YUYING_313LCD) set(BOARD_TYPE "kevin-yuying-313lcd") set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) @@ -149,9 +149,9 @@ elseif(CONFIG_BOARD_TYPE_KEVIN_YUYING_313LCD) set(DEFAULT_EMOJI_COLLECTION twemoji_64) elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV_S3) set(BOARD_TYPE "lichuang-dev") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_LICHUANG_DEV_C3) set(BOARD_TYPE "lichuang-c3-dev") set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) @@ -436,29 +436,29 @@ elseif(CONFIG_BOARD_TYPE_MOVECALL_CUICAN_ESP32S3) set(DEFAULT_EMOJI_COLLECTION twemoji_64) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3) set(BOARD_TYPE "atk-dnesp32s3") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX) set(BOARD_TYPE "atk-dnesp32s3-box") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX0) set(BOARD_TYPE "atk-dnesp32s3-box0") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_WIFI) set(BOARD_TYPE "atk-dnesp32s3-box2-wifi") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3_BOX2_4G) set(BOARD_TYPE "atk-dnesp32s3-box2-4g") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_ATK_DNESP32S3M_WIFI) set(BOARD_TYPE "atk-dnesp32s3m-wifi") set(BUILTIN_TEXT_FONT font_puhui_basic_16_4) @@ -499,24 +499,24 @@ elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_0_96OLED_ML307) set(BUILTIN_ICON_FONT font_awesome_14_1) elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_1_54TFT_WIFI) set(BOARD_TYPE "xingzhi-cube-1.54tft-wifi") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_XINGZHI_CUBE_1_54TFT_ML307) set(BOARD_TYPE "xingzhi-cube-1.54tft-ml307") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_XINGZHI_METAL_1_54_WIFI) set(BOARD_TYPE "xingzhi-metal-1.54-wifi") - set(BUILTIN_TEXT_FONT font_puhui_basic_20_4) + set(BUILTIN_TEXT_FONT font_noto_basic_20_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_SEEED_STUDIO_SENSECAP_WATCHER) set(BOARD_TYPE "sensecap-watcher") - set(BUILTIN_TEXT_FONT font_puhui_basic_30_4) + set(BUILTIN_TEXT_FONT font_noto_basic_30_4) set(BUILTIN_ICON_FONT font_awesome_20_4) - set(DEFAULT_EMOJI_COLLECTION twemoji_64) + set(DEFAULT_EMOJI_COLLECTION noto-emoji_128) elseif(CONFIG_BOARD_TYPE_DOIT_S3_AIBOX) set(BOARD_TYPE "doit-s3-aibox") elseif(CONFIG_BOARD_TYPE_MIXGO_NOVA) diff --git a/main/application.cc b/main/application.cc index f9c95cb8..3538d9d3 100644 --- a/main/application.cc +++ b/main/application.cc @@ -808,7 +808,8 @@ void Application::HandleStateChangedEvent() { case kDeviceStateUnknown: case kDeviceStateIdle: display->SetStatus(Lang::Strings::STANDBY); - display->SetEmotion("neutral"); + display->ClearChatMessages(); // Clear messages first + display->SetEmotion("neutral"); // Then set emotion (wechat mode checks child count) audio_service_.EnableVoiceProcessing(false); audio_service_.EnableWakeWordDetection(true); break; diff --git a/main/display/display.cc b/main/display/display.cc index d352e026..50fc1c52 100644 --- a/main/display/display.cc +++ b/main/display/display.cc @@ -45,6 +45,10 @@ void Display::SetChatMessage(const char* role, const char* content) { ESP_LOGW(TAG, " %s", content); } +void Display::ClearChatMessages() { + // Default empty implementation, override in subclasses if needed +} + void Display::SetTheme(Theme* theme) { current_theme_ = theme; Settings settings("display", true); diff --git a/main/display/display.h b/main/display/display.h index b24da4eb..f6139eee 100644 --- a/main/display/display.h +++ b/main/display/display.h @@ -35,6 +35,7 @@ public: virtual void ShowNotification(const std::string ¬ification, int duration_ms = 3000); virtual void SetEmotion(const char* emotion); virtual void SetChatMessage(const char* role, const char* content); + virtual void ClearChatMessages(); virtual void SetTheme(Theme* theme); virtual Theme* GetTheme() { return current_theme_; } virtual void UpdateStatusBar(bool update_all = false); diff --git a/main/display/lcd_display.cc b/main/display/lcd_display.cc index 03e1c84b..a6eb4f0e 100644 --- a/main/display/lcd_display.cc +++ b/main/display/lcd_display.cc @@ -556,7 +556,6 @@ void LcdDisplay::SetChatMessage(const char* role, const char* content) { } auto lvgl_theme = static_cast(current_theme_); - auto text_font = lvgl_theme->text_font()->font(); // Create a message bubble lv_obj_t* msg_bubble = lv_obj_create(content_); @@ -774,6 +773,26 @@ void LcdDisplay::SetPreviewImage(std::unique_ptr image) { // Auto-scroll to the image bubble lv_obj_scroll_to_view_recursive(img_bubble, LV_ANIM_ON); } + +void LcdDisplay::ClearChatMessages() { + DisplayLockGuard lock(this); + if (content_ == nullptr) { + return; + } + + // Use lv_obj_clean to delete all children of content_ (chat message bubbles) + lv_obj_clean(content_); + + // Reset chat_message_label_ as it has been deleted + chat_message_label_ = nullptr; + + // Show the centered AI logo (emoji_label_) again + if (emoji_label_ != nullptr) { + lv_obj_remove_flag(emoji_label_, LV_OBJ_FLAG_HIDDEN); + } + + ESP_LOGI(TAG, "Chat messages cleared"); +} #else void LcdDisplay::SetupUI() { DisplayLockGuard lock(this); @@ -891,29 +910,35 @@ void LcdDisplay::SetupUI() { lv_label_set_text(status_label_, Lang::Strings::INITIALIZING); lv_obj_align(status_label_, LV_ALIGN_CENTER, 0, 0); - /* Top layer: Bottom bar - fixed at bottom, minimum height 48, height can be adaptive */ + /* Top layer: Bottom bar - fixed height at bottom */ bottom_bar_ = lv_obj_create(screen); - lv_obj_set_width(bottom_bar_, LV_HOR_RES); - lv_obj_set_height(bottom_bar_, LV_SIZE_CONTENT); - lv_obj_set_style_min_height(bottom_bar_, 48, 0); // Set minimum height 48 + lv_obj_set_size(bottom_bar_, LV_HOR_RES, text_font->line_height + lvgl_theme->spacing(12)); lv_obj_set_style_radius(bottom_bar_, 0, 0); lv_obj_set_style_bg_color(bottom_bar_, lvgl_theme->background_color(), 0); lv_obj_set_style_text_color(bottom_bar_, lvgl_theme->text_color(), 0); - lv_obj_set_style_pad_top(bottom_bar_, lvgl_theme->spacing(2), 0); - lv_obj_set_style_pad_bottom(bottom_bar_, lvgl_theme->spacing(2), 0); + lv_obj_set_style_pad_all(bottom_bar_, 0, 0); lv_obj_set_style_pad_left(bottom_bar_, lvgl_theme->spacing(4), 0); lv_obj_set_style_pad_right(bottom_bar_, lvgl_theme->spacing(4), 0); lv_obj_set_style_border_width(bottom_bar_, 0, 0); + lv_obj_set_scrollbar_mode(bottom_bar_, LV_SCROLLBAR_MODE_OFF); lv_obj_align(bottom_bar_, LV_ALIGN_BOTTOM_MID, 0, 0); - /* chat_message_label_ placed in bottom_bar_ and vertically centered */ + /* chat_message_label_ placed in bottom_bar_, single-line horizontal scroll */ chat_message_label_ = lv_label_create(bottom_bar_); lv_label_set_text(chat_message_label_, ""); - lv_obj_set_width(chat_message_label_, LV_HOR_RES - lvgl_theme->spacing(8)); // Subtract left and right padding - lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_WRAP); // Auto wrap mode - lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_CENTER, 0); // Center text alignment + lv_obj_set_width(chat_message_label_, LV_HOR_RES - lvgl_theme->spacing(8)); + lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_SCROLL_CIRCULAR); + lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_CENTER, 0); lv_obj_set_style_text_color(chat_message_label_, lvgl_theme->text_color(), 0); - lv_obj_align(chat_message_label_, LV_ALIGN_CENTER, 0, 0); // Vertically and horizontally centered in bottom_bar_ + lv_obj_align(chat_message_label_, LV_ALIGN_CENTER, 0, 0); + + // Start scrolling after a delay (short text won't scroll) + static lv_anim_t a; + lv_anim_init(&a); + lv_anim_set_delay(&a, 1000); + lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE); + lv_obj_set_style_anim(chat_message_label_, &a, LV_PART_MAIN); + lv_obj_set_style_anim_duration(chat_message_label_, lv_anim_speed_clamped(60, 300, 60000), LV_PART_MAIN); low_battery_popup_ = lv_obj_create(screen); lv_obj_set_scrollbar_mode(low_battery_popup_, LV_SCROLLBAR_MODE_OFF); @@ -972,6 +997,14 @@ void LcdDisplay::SetChatMessage(const char* role, const char* content) { } lv_label_set_text(chat_message_label_, content); } + +void LcdDisplay::ClearChatMessages() { + DisplayLockGuard lock(this); + // In non-wechat mode, just clear the chat message label + if (chat_message_label_ != nullptr) { + lv_label_set_text(chat_message_label_, ""); + } +} #endif void LcdDisplay::SetEmotion(const char* emotion) { @@ -1005,6 +1038,8 @@ void LcdDisplay::SetEmotion(const char* emotion) { gif_controller_ = std::make_unique(image->image_dsc()); if (gif_controller_->IsLoaded()) { + // Set loop delay to 1000ms + gif_controller_->SetLoopDelay(3000); // Set up frame update callback gif_controller_->SetFrameCallback([this]() { lv_image_set_src(emoji_image_, gif_controller_->image_dsc()); diff --git a/main/display/lcd_display.h b/main/display/lcd_display.h index 1dc2a8d7..110b04d8 100644 --- a/main/display/lcd_display.h +++ b/main/display/lcd_display.h @@ -48,7 +48,8 @@ protected: public: ~LcdDisplay(); virtual void SetEmotion(const char* emotion) override; - virtual void SetChatMessage(const char* role, const char* content) override; + virtual void SetChatMessage(const char* role, const char* content) override; + virtual void ClearChatMessages() override; virtual void SetPreviewImage(std::unique_ptr image) override; // Add theme switching function diff --git a/main/display/lvgl_display/gif/lvgl_gif.cc b/main/display/lvgl_display/gif/lvgl_gif.cc index 172d5ba3..de002574 100644 --- a/main/display/lvgl_display/gif/lvgl_gif.cc +++ b/main/display/lvgl_display/gif/lvgl_gif.cc @@ -5,7 +5,8 @@ #define TAG "LvglGif" LvglGif::LvglGif(const lv_img_dsc_t* img_dsc) - : gif_(nullptr), timer_(nullptr), last_call_(0), playing_(false), loaded_(false) { + : gif_(nullptr), timer_(nullptr), last_call_(0), playing_(false), loaded_(false), + loop_delay_ms_(0), loop_waiting_(false), loop_wait_start_(0) { if (!img_dsc || !img_dsc->data) { ESP_LOGE(TAG, "Invalid image descriptor"); return; @@ -66,6 +67,7 @@ void LvglGif::Start() { if (timer_) { playing_ = true; + loop_waiting_ = false; // Reset loop waiting state last_call_ = lv_tick_get(); lv_timer_resume(timer_); lv_timer_reset(timer_); @@ -104,9 +106,15 @@ void LvglGif::Stop() { lv_timer_pause(timer_); } + // Reset loop waiting state + loop_waiting_ = false; + if (gif_) { gd_rewind(gif_); - NextFrame(); + // Render first frame without advancing + if (gif_->canvas) { + gd_render_frame(gif_, gif_->canvas); + } ESP_LOGD(TAG, "GIF animation stopped and rewound"); } } @@ -134,6 +142,15 @@ void LvglGif::SetLoopCount(int32_t count) { gif_->loop_count = count; } +uint32_t LvglGif::GetLoopDelay() const { + return loop_delay_ms_; +} + +void LvglGif::SetLoopDelay(uint32_t delay_ms) { + loop_delay_ms_ = delay_ms; + ESP_LOGD(TAG, "Loop delay set to %lu ms", delay_ms); +} + uint16_t LvglGif::width() const { if (!loaded_ || !gif_) { return 0; @@ -157,6 +174,18 @@ void LvglGif::NextFrame() { return; } + // Check if we're in loop wait state (only for infinite loop GIFs with delay) + if (loop_waiting_) { + uint32_t wait_elapsed = lv_tick_elaps(loop_wait_start_); + if (wait_elapsed < loop_delay_ms_) { + // Still waiting for loop delay + return; + } + // Loop delay completed, continue playing + loop_waiting_ = false; + ESP_LOGD(TAG, "Loop delay completed, continuing GIF"); + } + // Check if enough time has passed for the next frame uint32_t elapsed = lv_tick_elaps(last_call_); if (elapsed < gif_->gce.delay * 10) { @@ -165,15 +194,30 @@ void LvglGif::NextFrame() { last_call_ = lv_tick_get(); + // Save file position before getting next frame to detect loop + uint32_t pos_before = gif_->f_rw_p; + // Get next frame int has_next = gd_get_frame(gif_); if (has_next == 0) { - // Animation finished, pause timer + // Animation truly finished (non-infinite loop) playing_ = false; if (timer_) { lv_timer_pause(timer_); } ESP_LOGD(TAG, "GIF animation completed"); + return; + } + + // Detect loop by checking if file position jumped back (rewound to start) + // This works for looping GIFs regardless of when loop_count is set + if (loop_delay_ms_ > 0 && gif_->f_rw_p < pos_before) { + // File position decreased, meaning GIF looped back to beginning + // Start waiting before rendering this frame + loop_waiting_ = true; + loop_wait_start_ = lv_tick_get(); + ESP_LOGD(TAG, "GIF completed one cycle, waiting %lu ms before next loop", loop_delay_ms_); + return; } // Render current frame diff --git a/main/display/lvgl_display/gif/lvgl_gif.h b/main/display/lvgl_display/gif/lvgl_gif.h index afa2959e..17b9afd6 100644 --- a/main/display/lvgl_display/gif/lvgl_gif.h +++ b/main/display/lvgl_display/gif/lvgl_gif.h @@ -58,6 +58,17 @@ public: */ void SetLoopCount(int32_t count); + /** + * Get loop delay in milliseconds (delay between loops) + */ + uint32_t GetLoopDelay() const; + + /** + * Set loop delay in milliseconds (delay between loops) + * @param delay_ms Delay in milliseconds before starting next loop. 0 means no delay. + */ + void SetLoopDelay(uint32_t delay_ms); + /** * Get GIF dimensions */ @@ -86,6 +97,11 @@ private: bool playing_; bool loaded_; + // Loop delay configuration + uint32_t loop_delay_ms_; // Delay between loops in milliseconds + bool loop_waiting_; // Whether we're waiting for the next loop + uint32_t loop_wait_start_; // Timestamp when loop wait started + // Frame update callback std::function frame_callback_; diff --git a/main/idf_component.yml b/main/idf_component.yml index 8c636c7f..ae9ea509 100644 --- a/main/idf_component.yml +++ b/main/idf_component.yml @@ -27,7 +27,7 @@ dependencies: version: ~0.2.1 rules: - if: target not in [esp32] - 78/xiaozhi-fonts: ~1.5.5 + 78/xiaozhi-fonts: ~1.6.0 espressif/led_strip: ~3.0.2 espressif/esp_codec_dev: ~1.5.4 espressif/esp-sr: ~2.3.0 diff --git a/scripts/build_default_assets.py b/scripts/build_default_assets.py index a678a04d..9ca14646 100755 --- a/scripts/build_default_assets.py +++ b/scripts/build_default_assets.py @@ -693,7 +693,10 @@ def get_text_font_path(builtin_text_font, xiaozhi_fonts_path): # Convert from basic to common font name # e.g., font_puhui_basic_16_4 -> font_puhui_common_16_4.bin - font_name = builtin_text_font.replace('basic', 'common') + '.bin' + if builtin_text_font.startswith('font_noto_'): + font_name = builtin_text_font.replace('basic', 'qwen') + '.bin' + else: + font_name = builtin_text_font.replace('basic', 'common') + '.bin' font_path = os.path.join(xiaozhi_fonts_path, 'cbin', font_name) if os.path.exists(font_path): @@ -709,7 +712,8 @@ def get_emoji_collection_path(default_emoji_collection, xiaozhi_fonts_path, proj Returns the emoji directory path or None if no emoji collection is needed Supports: - - PNG emoji collections from xiaozhi-fonts (e.g., emojis_32) + - PNG emoji collections from xiaozhi-fonts (e.g., emojis_32, twemoji_64) + - GIF emoji collections from xiaozhi-fonts (e.g., noto-emoji_128, noto-emoji_64) - Otto GIF emoji collection (otto-gif) """ if not default_emoji_collection: @@ -729,13 +733,18 @@ def get_emoji_collection_path(default_emoji_collection, xiaozhi_fonts_path, proj print("Warning: project_root not provided, cannot locate otto-gif collection") return None - # Default behavior for PNG emoji collections + # Try PNG emoji collections first (e.g., emojis_32, twemoji_64) emoji_path = os.path.join(xiaozhi_fonts_path, 'png', default_emoji_collection) if os.path.exists(emoji_path): return emoji_path - else: - print(f"Warning: Emoji collection directory not found: {emoji_path}") - return None + + # Try GIF emoji collections (e.g., noto-emoji_128, noto-emoji_64, noto-emoji_32) + emoji_path = os.path.join(xiaozhi_fonts_path, 'gif', default_emoji_collection) + if os.path.exists(emoji_path): + return emoji_path + + print(f"Warning: Emoji collection directory not found in png/ or gif/: {default_emoji_collection}") + return None def build_assets_integrated(wakenet_model_paths, multinet_model_paths, text_font_path, emoji_collection_path, extra_files_path, output_path, multinet_model_info=None):