diff --git a/main/ui/apps/demo_app.cpp b/main/ui/apps/demo_app.cpp new file mode 100644 index 0000000..5d65300 --- /dev/null +++ b/main/ui/apps/demo_app.cpp @@ -0,0 +1,151 @@ +#include "apps/demo_app.h" +#include "esp_log.h" + +#define TAG "DemoApp" + +esp_err_t DemoApp::init(lv_obj_t* container) { + if (!container) { + ESP_LOGE(TAG, "Container is null"); + return ESP_ERR_INVALID_ARG; + } + + _container = container; + ESP_LOGI(TAG, "Initializing demo app..."); + + // Header label + _label_header = lv_label_create(_container); + lv_label_set_text(_label_header, "Counter & Brightness Demo"); + lv_obj_set_style_text_color(_label_header, lv_color_black(), 0); + lv_obj_align(_label_header, LV_ALIGN_TOP_MID, 0, 20); + + // Counter label + _label_counter = lv_label_create(_container); + lv_label_set_text(_label_counter, "Count: 0"); + lv_obj_set_style_text_color(_label_counter, lv_color_black(), 0); + lv_obj_align(_label_counter, LV_ALIGN_CENTER, 0, -80); + + // Increment button + _btn_increment = lv_btn_create(_container); + lv_obj_set_size(_btn_increment, 150, 60); + lv_obj_align(_btn_increment, LV_ALIGN_CENTER, -100, -20); + lv_obj_add_event_cb(_btn_increment, btn_increment_event_cb, LV_EVENT_CLICKED, this); + + lv_obj_t* label_inc = lv_label_create(_btn_increment); + lv_label_set_text(label_inc, "+"); + lv_obj_set_style_text_color(label_inc, lv_color_black(), 0); + lv_obj_center(label_inc); + + // Decrement button + _btn_decrement = lv_btn_create(_container); + lv_obj_set_size(_btn_decrement, 150, 60); + lv_obj_align(_btn_decrement, LV_ALIGN_CENTER, 100, -20); + lv_obj_add_event_cb(_btn_decrement, btn_decrement_event_cb, LV_EVENT_CLICKED, this); + + lv_obj_t* label_dec = lv_label_create(_btn_decrement); + lv_label_set_text(label_dec, "-"); + lv_obj_set_style_text_color(label_dec, lv_color_black(), 0); + lv_obj_center(label_dec); + + // Slider + _slider_brightness = lv_slider_create(_container); + lv_obj_set_width(_slider_brightness, 400); + lv_obj_align(_slider_brightness, LV_ALIGN_CENTER, 0, 80); + lv_slider_set_range(_slider_brightness, 0, 100); + lv_slider_set_value(_slider_brightness, 50, LV_ANIM_OFF); + lv_obj_add_event_cb(_slider_brightness, slider_event_cb, LV_EVENT_VALUE_CHANGED, this); + + // Slider value label + _label_slider_value = lv_label_create(_container); + lv_label_set_text(_label_slider_value, "Brightness: 50%"); + lv_obj_set_style_text_color(_label_slider_value, lv_color_black(), 0); + lv_obj_align(_label_slider_value, LV_ALIGN_CENTER, 0, 130); + + // Info text at bottom + lv_obj_t* label_info = lv_label_create(_container); + lv_label_set_text(label_info, "Touch buttons and slider to test"); + lv_obj_set_style_text_color(label_info, lv_color_black(), 0); + lv_obj_align(label_info, LV_ALIGN_BOTTOM_MID, 0, -20); + + ESP_LOGI(TAG, "Demo app initialized successfully"); + return ESP_OK; +} + +esp_err_t DemoApp::deinit(void) { + ESP_LOGI(TAG, "Deinitializing demo app"); + + // All widgets will be automatically deleted when container is cleaned + _label_header = nullptr; + _label_counter = nullptr; + _btn_increment = nullptr; + _btn_decrement = nullptr; + _slider_brightness = nullptr; + _label_slider_value = nullptr; + _counter = 0; + + return ESP_OK; +} + +std::string DemoApp::get_name(void) const { + return "Demo"; +} + +void DemoApp::btn_increment_event_cb(lv_event_t* e) { + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + DemoApp* app = (DemoApp*)lv_event_get_user_data(e); + if (app) { + app->_counter++; + lv_label_set_text_fmt(app->_label_counter, "Count: %d", app->_counter); + ESP_LOGI(TAG, "Increment button clicked, count: %d", app->_counter); + } + } +} + +void DemoApp::btn_decrement_event_cb(lv_event_t* e) { + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_CLICKED) { + DemoApp* app = (DemoApp*)lv_event_get_user_data(e); + if (app) { + app->_counter--; + lv_label_set_text_fmt(app->_label_counter, "Count: %d", app->_counter); + ESP_LOGI(TAG, "Decrement button clicked, count: %d", app->_counter); + } + } +} + +void DemoApp::slider_event_cb(lv_event_t* e) { + lv_event_code_t code = lv_event_get_code(e); + if (code == LV_EVENT_VALUE_CHANGED) { + DemoApp* app = (DemoApp*)lv_event_get_user_data(e); + if (app) { + lv_obj_t* slider = (lv_obj_t*)lv_event_get_target(e); + int32_t value = lv_slider_get_value(slider); + lv_label_set_text_fmt(app->_label_slider_value, "Brightness: %d%%", (int)value); + ESP_LOGI(TAG, "Slider value changed: %d", (int)value); + } + } +} + +// DemoAppDescriptor implementation +DemoApp* DemoAppDescriptor::_app_instance = nullptr; + +DemoAppDescriptor::DemoAppDescriptor() + : AppDescriptor("Demo", nullptr) { + // Create singleton app instance + if (!_app_instance) { + _app_instance = new DemoApp(); + } + + // Register with AppRegistry + AppRegistry::instance().register_app(this); + ESP_LOGI(TAG, "DemoApp registered with AppRegistry"); +} + +void DemoAppDescriptor::draw_icon(lv_obj_t* parent) { + // Create a simple icon with text and a symbol + lv_obj_t* icon_label = lv_label_create(parent); + lv_label_set_text(icon_label, LV_SYMBOL_SETTINGS "\nDemo"); + lv_obj_set_style_text_color(icon_label, lv_color_white(), 0); + lv_obj_set_style_text_align(icon_label, LV_TEXT_ALIGN_CENTER, 0); + lv_obj_center(icon_label); +} diff --git a/main/ui/apps/shutdown_app.cpp b/main/ui/apps/shutdown_app.cpp new file mode 100644 index 0000000..19593cd --- /dev/null +++ b/main/ui/apps/shutdown_app.cpp @@ -0,0 +1,64 @@ +#include "apps/shutdown_app.h" +#include "esp_log.h" + +#define TAG "ShutdownApp" + +ShutdownApp::ShutdownApp(std::string message) + : _message(message.empty() ? "System Shutting Down..." : message) { } + +esp_err_t ShutdownApp::init(lv_obj_t* container) { + if (!container) { + ESP_LOGE(TAG, "Container is null"); + return ESP_ERR_INVALID_ARG; + } + + _container = container; + ESP_LOGI(TAG, "Initializing shutdown app with message: %s", _message.c_str()); + + // Main message label + _label_message = lv_label_create(_container); + lv_label_set_text(_label_message, _message.c_str()); + lv_obj_set_style_text_color(_label_message, lv_color_white(), 0); + lv_obj_align(_label_message, LV_ALIGN_CENTER, 0, 0); + + // Optional: Add spinner animation + lv_obj_t* spinner = lv_spinner_create(_container); + lv_obj_set_size(spinner, 80, 80); + lv_obj_align(spinner, LV_ALIGN_CENTER, 0, 80); + lv_obj_set_style_arc_color(spinner, lv_color_white(), LV_PART_INDICATOR); + + ESP_LOGI(TAG, "Shutdown app initialized successfully"); + return ESP_OK; +} + +esp_err_t ShutdownApp::deinit(void) { + ESP_LOGI(TAG, "Deinitializing shutdown app"); + _label_message = nullptr; + return ESP_OK; +} + +std::string ShutdownApp::get_name(void) const { + return "Shutdown"; +} + +// ShutdownAppDescriptor implementation +ShutdownApp* ShutdownAppDescriptor::_app_instance = nullptr; + +ShutdownAppDescriptor::ShutdownAppDescriptor() + : AppDescriptor("Shutdown", nullptr) { + // Create singleton app instance with default message + if (!_app_instance) { + _app_instance = new ShutdownApp(); + } + + // it's only used during system shutdown, not as a user-launchable app +} + +void ShutdownAppDescriptor::draw_icon(lv_obj_t* parent) { + // Create a simple icon (not normally shown in nav bar) + lv_obj_t* icon_label = lv_label_create(parent); + lv_label_set_text(icon_label, LV_SYMBOL_POWER "\nShutdown"); + lv_obj_set_style_text_color(icon_label, lv_color_white(), 0); + lv_obj_set_style_text_align(icon_label, LV_TEXT_ALIGN_CENTER, 0); + lv_obj_center(icon_label); +}