- Added MainUI class for displaying voice state, status icon, and buttons. - Introduced MainUIHandler to manage UI interactions and bridge communication. - Created SettingsUI for displaying QR code and configuration instructions. - Implemented SettingsUIHandler to manage settings and web server interactions. - Developed WebHandler for handling HTTP requests for settings configuration. - Updated AppRegistry to initialize with the new Discord app descriptor. - Enhanced InteractionHandler to support keyboard interactions across app switches. - Updated UIHandler to manage app switching and rendering of app icons. - Enabled QR code support in LVGL configuration.
180 lines
4.6 KiB
C++
180 lines
4.6 KiB
C++
#include "ui/interaction_handler.h"
|
|
#include "ui/events.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
|
|
#define TAG "InteractionHandler"
|
|
|
|
InteractionHandler::~InteractionHandler() {
|
|
esp_err_t err = deinit();
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Error during InteractionHandler deinit: %s", esp_err_to_name(err));
|
|
}
|
|
}
|
|
|
|
esp_err_t InteractionHandler::init(lv_obj_t* parent_container) {
|
|
if (!parent_container) {
|
|
ESP_LOGE(TAG, "Invalid argument: parent_container is nullptr");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
parent_container_ = parent_container;
|
|
|
|
keyboard_ = lv_keyboard_create(parent_container_);
|
|
if (!keyboard_) {
|
|
ESP_LOGE(TAG, "Failed to create keyboard object");
|
|
return ESP_ERR_NO_MEM;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Keyboard created successfully at %p", keyboard_);
|
|
lv_obj_add_flag(keyboard_, LV_OBJ_FLAG_HIDDEN); // start hidden
|
|
lv_obj_add_event_cb(
|
|
keyboard_,
|
|
[](lv_event_t* e) {
|
|
InteractionHandler* handler = static_cast<InteractionHandler*>(lv_event_get_user_data(e));
|
|
handler->on_keyboard_event_(e);
|
|
}
|
|
, LV_EVENT_ALL, this);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t InteractionHandler::deinit(void) {
|
|
if (keyboard_) {
|
|
lv_obj_del(keyboard_);
|
|
keyboard_ = nullptr;
|
|
}
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t InteractionHandler::register_text_area_keyboard_support(lv_obj_t* text_area) {
|
|
if (!text_area) {
|
|
ESP_LOGE(TAG, "Invalid argument: text_area is nullptr");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
lv_obj_add_event_cb(
|
|
text_area,
|
|
[](lv_event_t* e) {
|
|
lv_event_code_t code = lv_event_get_code(e);
|
|
if (code != LV_EVENT_FOCUSED) {
|
|
return;
|
|
}
|
|
InteractionHandler* handler = static_cast<InteractionHandler*>(lv_event_get_user_data(e));
|
|
|
|
esp_err_t err = handler->show_keyboard_for_textarea_(static_cast<lv_obj_t*>(lv_event_get_target(e)));
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to show keyboard: %s", esp_err_to_name(err));
|
|
}
|
|
}
|
|
, LV_EVENT_FOCUSED, this);
|
|
|
|
lv_obj_add_event_cb(
|
|
text_area,
|
|
[](lv_event_t* e) {
|
|
lv_event_code_t code = lv_event_get_code(e);
|
|
if (code != LV_EVENT_DEFOCUSED) {
|
|
return;
|
|
}
|
|
InteractionHandler* handler = static_cast<InteractionHandler*>(lv_event_get_user_data(e));
|
|
|
|
esp_err_t err = handler->hide_keyboard_();
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to hide keyboard: %s", esp_err_to_name(err));
|
|
}
|
|
}
|
|
, LV_EVENT_DEFOCUSED, this);
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
//
|
|
// Private methods
|
|
//
|
|
|
|
void InteractionHandler::on_keyboard_event_(lv_event_t* e) {
|
|
lv_event_code_t code = lv_event_get_code(e);
|
|
if (code == LV_EVENT_READY || code == LV_EVENT_CANCEL) {
|
|
// Keyboard is cancelled
|
|
esp_err_t err = hide_keyboard_();
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to hide keyboard: %s", esp_err_to_name(err));
|
|
}
|
|
|
|
if (focused_textarea_) {
|
|
lv_obj_clear_state(focused_textarea_, LV_STATE_FOCUSED);
|
|
lv_keyboard_set_textarea(keyboard_, nullptr);
|
|
focused_textarea_ = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
esp_err_t InteractionHandler::show_keyboard_for_textarea_(lv_obj_t* textarea) {
|
|
if (!textarea) {
|
|
ESP_LOGE(TAG, "Invalid argument: textarea is nullptr");
|
|
return ESP_ERR_INVALID_ARG;
|
|
}
|
|
|
|
if (!keyboard_) {
|
|
ESP_LOGE(TAG, "Keyboard object is nullptr - was InteractionHandler properly initialized?");
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
// Verify keyboard object is still valid
|
|
if (!lv_obj_is_valid(keyboard_)) {
|
|
ESP_LOGE(TAG, "Keyboard object is no longer valid - it may have been deleted");
|
|
keyboard_ = nullptr;
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Showing keyboard for textarea %p", textarea);
|
|
focused_textarea_ = textarea;
|
|
lv_keyboard_set_textarea(keyboard_, textarea);
|
|
lv_obj_clear_flag(keyboard_, LV_OBJ_FLAG_HIDDEN);
|
|
// emit keyboard shown event
|
|
KeyboardEventData event_data = {
|
|
.textarea = textarea
|
|
};
|
|
esp_err_t err = esp_event_post_to(
|
|
NULL,
|
|
UI_EVENT_BASE,
|
|
UI_EVENT_KEYBOARD_SHOWN,
|
|
&event_data,
|
|
sizeof(event_data),
|
|
portMAX_DELAY
|
|
);
|
|
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to post keyboard shown event: %s", esp_err_to_name(err));
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
esp_err_t InteractionHandler::hide_keyboard_(void) {
|
|
if (!keyboard_) {
|
|
return ESP_ERR_INVALID_STATE;
|
|
}
|
|
|
|
lv_obj_add_flag(keyboard_, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
// emit keyboard hidden event
|
|
KeyboardEventData event_data = {
|
|
.textarea = nullptr
|
|
};
|
|
|
|
esp_err_t err = esp_event_post_to(
|
|
NULL,
|
|
UI_EVENT_BASE,
|
|
UI_EVENT_KEYBOARD_HIDDEN,
|
|
&event_data,
|
|
sizeof(event_data),
|
|
portMAX_DELAY
|
|
);
|
|
|
|
if (err != ESP_OK) {
|
|
ESP_LOGE(TAG, "Failed to post keyboard hidden event: %s", esp_err_to_name(err));
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|