Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions main/Kconfig.projbuild
Original file line number Diff line number Diff line change
Expand Up @@ -399,13 +399,9 @@ choice BOARD_TYPE
config BOARD_TYPE_OTTO_ROBOT
bool "ottoRobot"
depends on IDF_TARGET_ESP32S3
select LV_USE_GIF
select LV_GIF_CACHE_DECODE_DATA
config BOARD_TYPE_ELECTRON_BOT
bool "electronBot"
depends on IDF_TARGET_ESP32S3
select LV_USE_GIF
select LV_GIF_CACHE_DECODE_DATA
config BOARD_TYPE_JIUCHUAN
bool "九川智能"
depends on IDF_TARGET_ESP32S3
Expand Down
2 changes: 1 addition & 1 deletion main/boards/electron-bot/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@

#define BOOT_BUTTON_GPIO GPIO_NUM_0

#define ELECTRON_BOT_VERSION "1.1.3"
#define ELECTRON_BOT_VERSION "2.0.4"
#endif // _BOARD_CONFIG_H_
4 changes: 1 addition & 3 deletions main/boards/electron-bot/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
"builds": [
{
"name": "electron-bot",
"sdkconfig_append": [
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v1/16m.csv\""
]
"sdkconfig_append": []
}
]
}
207 changes: 98 additions & 109 deletions main/boards/electron-bot/electron_emoji_display.cc
Original file line number Diff line number Diff line change
@@ -1,150 +1,139 @@
#include "electron_emoji_display.h"
#include "lvgl_theme.h"

#include <esp_log.h>
#include <font_awesome.h>

#include <algorithm>
#include <cstring>
#include <string>

#include "assets/lang_config.h"
#include "display/lvgl_display/emoji_collection.h"
#include "display/lvgl_display/lvgl_image.h"
#include "display/lvgl_display/lvgl_theme.h"
#include "otto_emoji_gif.h"

#define TAG "ElectronEmojiDisplay"
ElectronEmojiDisplay::ElectronEmojiDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(panel_io, panel, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy) {
InitializeElectronEmojis();
SetupChatLabel();
}

void ElectronEmojiDisplay::InitializeElectronEmojis() {
ESP_LOGI(TAG, "初始化Electron GIF表情");

auto otto_emoji_collection = std::make_shared<EmojiCollection>();

// 表情映射表 - 将多种表情映射到现有6个GIF
const ElectronEmojiDisplay::EmotionMap ElectronEmojiDisplay::emotion_maps_[] = {
// 中性/平静类表情 -> staticstate
{"neutral", &staticstate},
{"relaxed", &staticstate},
{"sleepy", &staticstate},
otto_emoji_collection->AddEmoji("staticstate", new LvglRawImage((void*)staticstate.data, staticstate.data_size));
otto_emoji_collection->AddEmoji("neutral", new LvglRawImage((void*)staticstate.data, staticstate.data_size));
otto_emoji_collection->AddEmoji("relaxed", new LvglRawImage((void*)staticstate.data, staticstate.data_size));
otto_emoji_collection->AddEmoji("sleepy", new LvglRawImage((void*)staticstate.data, staticstate.data_size));
otto_emoji_collection->AddEmoji("idle", new LvglRawImage((void*)staticstate.data, staticstate.data_size));

// 积极/开心类表情 -> happy
{"happy", &happy},
{"laughing", &happy},
{"funny", &happy},
{"loving", &happy},
{"confident", &happy},
{"winking", &happy},
{"cool", &happy},
{"delicious", &happy},
{"kissy", &happy},
{"silly", &happy},
otto_emoji_collection->AddEmoji("happy", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("laughing", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("funny", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("loving", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("confident", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("winking", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("cool", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("delicious", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("kissy", new LvglRawImage((void*)happy.data, happy.data_size));
otto_emoji_collection->AddEmoji("silly", new LvglRawImage((void*)happy.data, happy.data_size));

// 悲伤类表情 -> sad
{"sad", &sad},
{"crying", &sad},
otto_emoji_collection->AddEmoji("sad", new LvglRawImage((void*)sad.data, sad.data_size));
otto_emoji_collection->AddEmoji("crying", new LvglRawImage((void*)sad.data, sad.data_size));

// 愤怒类表情 -> anger
{"angry", &anger},
otto_emoji_collection->AddEmoji("anger", new LvglRawImage((void*)anger.data, anger.data_size));
otto_emoji_collection->AddEmoji("angry", new LvglRawImage((void*)anger.data, anger.data_size));

// 惊讶类表情 -> scare
{"surprised", &scare},
{"shocked", &scare},
otto_emoji_collection->AddEmoji("scare", new LvglRawImage((void*)scare.data, scare.data_size));
otto_emoji_collection->AddEmoji("surprised", new LvglRawImage((void*)scare.data, scare.data_size));
otto_emoji_collection->AddEmoji("shocked", new LvglRawImage((void*)scare.data, scare.data_size));

// 思考/困惑类表情 -> buxue
{"thinking", &buxue},
{"confused", &buxue},
{"embarrassed", &buxue},

{nullptr, nullptr} // 结束标记
};

ElectronEmojiDisplay::ElectronEmojiDisplay(esp_lcd_panel_io_handle_t panel_io,
esp_lcd_panel_handle_t panel, int width, int height,
int offset_x, int offset_y, bool mirror_x, bool mirror_y,
bool swap_xy)
: SpiLcdDisplay(panel_io, panel, width, height, offset_x, offset_y, mirror_x, mirror_y, swap_xy),
emotion_gif_(nullptr) {
SetupGifContainer();
}
otto_emoji_collection->AddEmoji("buxue", new LvglRawImage((void*)buxue.data, buxue.data_size));
otto_emoji_collection->AddEmoji("thinking", new LvglRawImage((void*)buxue.data, buxue.data_size));
otto_emoji_collection->AddEmoji("confused", new LvglRawImage((void*)buxue.data, buxue.data_size));
otto_emoji_collection->AddEmoji("embarrassed", new LvglRawImage((void*)buxue.data, buxue.data_size));

void ElectronEmojiDisplay::SetupGifContainer() {
DisplayLockGuard lock(this);
// 将表情集合添加到主题中
auto& theme_manager = LvglThemeManager::GetInstance();
auto light_theme = theme_manager.GetTheme("light");
auto dark_theme = theme_manager.GetTheme("dark");

if (emoji_label_) {
lv_obj_del(emoji_label_);
}
if (chat_message_label_) {
lv_obj_del(chat_message_label_);
if (light_theme != nullptr) {
light_theme->set_emoji_collection(otto_emoji_collection);
}
if (content_) {
lv_obj_del(content_);
if (dark_theme != nullptr) {
dark_theme->set_emoji_collection(otto_emoji_collection);
}

content_ = lv_obj_create(container_);
lv_obj_set_scrollbar_mode(content_, LV_SCROLLBAR_MODE_OFF);
lv_obj_set_size(content_, LV_HOR_RES, LV_HOR_RES);
lv_obj_set_style_bg_opa(content_, LV_OPA_TRANSP, 0);
lv_obj_set_style_border_width(content_, 0, 0);
lv_obj_set_flex_grow(content_, 1);
lv_obj_center(content_);

emoji_label_ = lv_label_create(content_);
lv_label_set_text(emoji_label_, "");
lv_obj_set_width(emoji_label_, 0);
lv_obj_set_style_border_width(emoji_label_, 0, 0);
lv_obj_add_flag(emoji_label_, LV_OBJ_FLAG_HIDDEN);

emotion_gif_ = lv_gif_create(content_);
int gif_size = LV_HOR_RES;
lv_obj_set_size(emotion_gif_, gif_size, gif_size);
lv_obj_set_style_border_width(emotion_gif_, 0, 0);
lv_obj_set_style_bg_opa(emotion_gif_, LV_OPA_TRANSP, 0);
lv_obj_center(emotion_gif_);
lv_gif_set_src(emotion_gif_, &staticstate);

chat_message_label_ = lv_label_create(content_);
lv_label_set_text(chat_message_label_, "");
lv_obj_set_width(chat_message_label_, LV_HOR_RES * 0.9);
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_, lv_color_white(), 0);
lv_obj_set_style_border_width(chat_message_label_, 0, 0);
// 设置默认表情为staticstate
SetEmotion("staticstate");

lv_obj_set_style_bg_opa(chat_message_label_, LV_OPA_70, 0);
lv_obj_set_style_bg_color(chat_message_label_, lv_color_black(), 0);
lv_obj_set_style_pad_ver(chat_message_label_, 5, 0);

lv_obj_align(chat_message_label_, LV_ALIGN_BOTTOM_MID, 0, 0);

auto& theme_manager = LvglThemeManager::GetInstance();
auto theme = theme_manager.GetTheme("dark");
if (theme != nullptr) {
LcdDisplay::SetTheme(theme);
}
ESP_LOGI(TAG, "Electron GIF表情初始化完成");
}

void ElectronEmojiDisplay::SetEmotion(const char* emotion) {
if (!emotion || !emotion_gif_) {
return;
}

void ElectronEmojiDisplay::SetupChatLabel() {
DisplayLockGuard lock(this);

for (const auto& map : emotion_maps_) {
if (map.name && strcmp(map.name, emotion) == 0) {
lv_gif_set_src(emotion_gif_, map.gif);
ESP_LOGI(TAG, "设置表情: %s", emotion);
return;
}
if (chat_message_label_) {
lv_obj_del(chat_message_label_);
}

lv_gif_set_src(emotion_gif_, &staticstate);
ESP_LOGI(TAG, "未知表情'%s',使用默认", emotion);
chat_message_label_ = lv_label_create(container_);
lv_label_set_text(chat_message_label_, "");
lv_obj_set_width(chat_message_label_, width_ * 0.9); // 限制宽度为屏幕宽度的 90%
lv_label_set_long_mode(chat_message_label_, LV_LABEL_LONG_WRAP); // 设置为自动换行模式
lv_obj_set_style_text_align(chat_message_label_, LV_TEXT_ALIGN_CENTER, 0); // 设置文本居中对齐
lv_obj_set_style_text_color(chat_message_label_, lv_color_white(), 0);
SetTheme(LvglThemeManager::GetInstance().GetTheme("dark"));
}

void ElectronEmojiDisplay::SetChatMessage(const char* role, const char* content) {
LV_FONT_DECLARE(OTTO_ICON_FONT);
void ElectronEmojiDisplay::SetStatus(const char* status) {
auto lvgl_theme = static_cast<LvglTheme*>(current_theme_);
auto text_font = lvgl_theme->text_font()->font();
DisplayLockGuard lock(this);
if (chat_message_label_ == nullptr) {
if (!status) {
ESP_LOGE(TAG, "SetStatus: status is nullptr");
return;
}

if (content == nullptr || strlen(content) == 0) {
lv_obj_add_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);
if (strcmp(status, Lang::Strings::LISTENING) == 0) {
lv_obj_set_style_text_font(status_label_, &OTTO_ICON_FONT, 0);
lv_label_set_text(status_label_, "\xEF\x84\xB0"); // U+F130 麦克风图标
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(network_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(battery_label_, LV_OBJ_FLAG_HIDDEN);
return;
} else if (strcmp(status, Lang::Strings::SPEAKING) == 0) {
lv_obj_set_style_text_font(status_label_, &OTTO_ICON_FONT, 0);
lv_label_set_text(status_label_, "\xEF\x80\xA8"); // U+F028 说话图标
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(network_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_add_flag(battery_label_, LV_OBJ_FLAG_HIDDEN);
return;
} else if (strcmp(status, Lang::Strings::CONNECTING) == 0) {
lv_obj_set_style_text_font(status_label_, &OTTO_ICON_FONT, 0);
lv_label_set_text(status_label_, "\xEF\x83\x81"); // U+F0c1 连接图标
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
return;
} else if (strcmp(status, Lang::Strings::STANDBY) == 0) {
lv_obj_set_style_text_font(status_label_, text_font, 0);
lv_label_set_text(status_label_, "");
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
return;
}

lv_label_set_text(chat_message_label_, content);
lv_obj_remove_flag(chat_message_label_, LV_OBJ_FLAG_HIDDEN);

ESP_LOGI(TAG, "设置聊天消息 [%s]: %s", role, content);
lv_obj_set_style_text_font(status_label_, text_font, 0);
lv_label_set_text(status_label_, status);
lv_obj_clear_flag(status_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(network_label_, LV_OBJ_FLAG_HIDDEN);
lv_obj_clear_flag(battery_label_, LV_OBJ_FLAG_HIDDEN);
}
42 changes: 8 additions & 34 deletions main/boards/electron-bot/electron_emoji_display.h
Original file line number Diff line number Diff line change
@@ -1,48 +1,22 @@
#pragma once

#include <libs/gif/lv_gif.h>

#include "display/lcd_display.h"

// Electron Bot表情GIF声明 - 使用与Otto相同的6个表情
LV_IMAGE_DECLARE(staticstate); // 静态状态/中性表情
LV_IMAGE_DECLARE(sad); // 悲伤
LV_IMAGE_DECLARE(happy); // 开心
LV_IMAGE_DECLARE(scare); // 惊吓/惊讶
LV_IMAGE_DECLARE(buxue); // 不学/困惑
LV_IMAGE_DECLARE(anger); // 愤怒

/**
* @brief Electron Bot GIF表情显示类
* 继承LcdDisplay,添加GIF表情支持
* @brief Electron机器人GIF表情显示类
* 继承SpiLcdDisplay,通过EmojiCollection添加GIF表情支持
*/
class ElectronEmojiDisplay : public SpiLcdDisplay {
public:
public:
/**
* @brief 构造函数,参数与SpiLcdDisplay相同
*/
ElectronEmojiDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel,
int width, int height, int offset_x, int offset_y, bool mirror_x,
bool mirror_y, bool swap_xy);
ElectronEmojiDisplay(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_handle_t panel, int width, int height, int offset_x, int offset_y, bool mirror_x, bool mirror_y, bool swap_xy);

virtual ~ElectronEmojiDisplay() = default;
virtual void SetStatus(const char* status) override;

// 重写表情设置方法
virtual void SetEmotion(const char* emotion) override;

// 重写聊天消息设置方法
virtual void SetChatMessage(const char* role, const char* content) override;

private:
void SetupGifContainer();

lv_obj_t* emotion_gif_; ///< GIF表情组件

// 表情映射
struct EmotionMap {
const char* name;
const lv_image_dsc_t* gif;
};

static const EmotionMap emotion_maps_[];
private:
void InitializeElectronEmojis();
void SetupChatLabel();
};
Loading
Loading