Files
ink-board/main/ui/ui_handler.cpp

209 lines
5.2 KiB
C++

#include "ui/ui_handler.h"
#include "ui/root_layout.h"
#include "ui/app_registry.h"
#include "esp_log.h"
#include "lvgl.h"
#define TAG "UIHandler"
// Display dimensions from constants.h
#define DISPLAY_WIDTH 800
#define DISPLAY_HEIGHT 480
// Layout dimensions
#define HEADER_HEIGHT 40
#define NAV_BAR_HEIGHT 50
#define _APP_CONTAINERHEIGHT (DISPLAY_HEIGHT - HEADER_HEIGHT - NAV_BAR_HEIGHT)
esp_err_t UIHandler::init(void) {
ESP_LOGI(TAG, "Initializing UIHandler");
// Create main screen
_main_screen = lv_obj_create(NULL);
if (!_main_screen) {
ESP_LOGE(TAG, "Failed to create main screen");
return ESP_FAIL;
}
lv_obj_set_style_bg_color(_main_screen, lv_color_black(), 0);
lv_obj_set_size(_main_screen, DISPLAY_WIDTH, DISPLAY_HEIGHT);
// Create root layout
_root_layout = new RootLayout(this);
if (!_root_layout) {
ESP_LOGE(TAG, "Failed to allocate RootLayout");
return ESP_FAIL;
}
if (_root_layout->init(_main_screen) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize root layout");
delete _root_layout;
_root_layout = nullptr;
return ESP_FAIL;
}
// Render app icons from registry
if (_root_layout->render_app_icons() != ESP_OK) {
ESP_LOGW(TAG, "Failed to render app icons");
}
// Defer screen loading to prevent blocking during initialization
// Use LVGL timer to load screen after allowing watchdog reset
lv_timer_create([](lv_timer_t* timer) {
lv_obj_t* screen = static_cast<lv_obj_t*>(lv_timer_get_user_data(timer));
ESP_LOGI("UIHandler", "Loading main screen via timer");
lv_screen_load(screen);
lv_timer_del(timer);
}, 100, _main_screen); // 100ms delay to allow watchdog reset
ESP_LOGI(TAG, "UIHandler initialized successfully");
return ESP_OK;
}
esp_err_t UIHandler::deinit(void) {
ESP_LOGI(TAG, "Deinitializing UIHandler");
// Deinit current app
if (_active_app) {
if (_active_app->deinit() != ESP_OK) {
ESP_LOGW(TAG, "Error deinitializing active app: %s", _active_app->get_name());
}
_active_app = nullptr;
}
// Delete shutdown app if cached
if (_shutdown_app) {
delete _shutdown_app;
_shutdown_app = nullptr;
}
// Clean up root layout
if (_root_layout) {
_root_layout->deinit();
delete _root_layout;
_root_layout = nullptr;
}
// Main screen will be cleaned up by LVGL
_main_screen = nullptr;
return ESP_OK;
}
esp_err_t UIHandler::switch_app(UIApp* app) {
if (!app) {
ESP_LOGE(TAG, "Cannot switch to null app");
return ESP_ERR_INVALID_ARG;
}
lv_obj_t* app_container = get_app_container();
if (!app_container) {
ESP_LOGE(TAG, "App container not initialized");
return ESP_FAIL;
}
ESP_LOGI(TAG, "Switching to app: %s", app->get_name());
// Deinit current app
if (_active_app) {
if (_active_app->deinit() != ESP_OK) {
ESP_LOGW(TAG, "Error deinitializing app: %s", _active_app->get_name());
}
}
// Clear the app container
lv_obj_clean(app_container);
// Initialize new app
if (app->init(app_container) != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize app: %s", app->get_name());
_active_app = nullptr;
return ESP_FAIL;
}
_active_app = app;
// Update header through RootLayout
if (_root_layout) {
_root_layout->update_header(_active_app->get_name());
_root_layout->show_back_button();
}
return ESP_OK;
}
esp_err_t UIHandler::switch_app(AppDescriptor* app_descriptor) {
if (!app_descriptor) {
ESP_LOGE(TAG, "Cannot switch to null app descriptor");
return ESP_ERR_INVALID_ARG;
}
UIApp* app = app_descriptor->get_app_instance();
if (!app) {
ESP_LOGE(TAG, "App descriptor has null app instance");
return ESP_ERR_INVALID_ARG;
}
return switch_app(app);
}
void UIHandler::route_event(uint32_t event_type, void* event_data) {
if (_active_app) {
_active_app->handle_event(event_type, event_data);
}
}
esp_err_t UIHandler::show_shutdown_screen(std::string message) {
ESP_LOGI(TAG, "Showing shutdown screen");
lv_obj_t* app_container = get_app_container();
if (!app_container) {
ESP_LOGE(TAG, "App container not initialized");
return ESP_FAIL;
}
// Clear current app reference
_active_app = nullptr;
// Clear the app container
lv_obj_clean(app_container);
// Create shutdown message
lv_obj_t* shutdown_label = lv_label_create(app_container);
lv_label_set_text(shutdown_label, message.empty() ? "Shutting down..." : message.c_str());
lv_obj_set_style_text_color(shutdown_label, lv_color_white(), 0);
lv_obj_align(shutdown_label, LV_ALIGN_CENTER, 0, 0);
// Update header through RootLayout
if (_root_layout) {
_root_layout->update_header("System Shutdown");
}
return ESP_OK;
}
esp_err_t UIHandler::return_to_main_screen(void) {
ESP_LOGI(TAG, "Returning to main screen");
// Deinit current app
if (_active_app) {
if (_active_app->deinit() != ESP_OK) {
ESP_LOGW(TAG, "Error deinitializing app: %s", _active_app->get_name());
}
_active_app = nullptr;
}
// Clear the app container
lv_obj_t* app_container = get_app_container();
if (app_container) {
lv_obj_clean(app_container);
}
// Update header and hide back button through RootLayout
if (_root_layout) {
_root_layout->update_header("");
_root_layout->hide_back_button();
}
return ESP_OK;
}