From ac4190c29cdbc3919faa7c674d6ba0dc5ad00874 Mon Sep 17 00:00:00 2001 From: Ken Van Hoeylandt Date: Mon, 8 Sep 2025 18:19:03 +0200 Subject: [PATCH] UX improvements --- Tactility/Source/app/boot/Boot.cpp | 10 ++- .../Source/app/calculator/Calculator.cpp | 6 +- Tactility/Source/app/chat/ChatApp.cpp | 82 ++++++------------- 3 files changed, 37 insertions(+), 61 deletions(-) diff --git a/Tactility/Source/app/boot/Boot.cpp b/Tactility/Source/app/boot/Boot.cpp index 65f0d331..f36e7a66 100644 --- a/Tactility/Source/app/boot/Boot.cpp +++ b/Tactility/Source/app/boot/Boot.cpp @@ -83,10 +83,18 @@ class BootApp : public App { static int32_t bootThreadCallback() { const auto start_time = kernel::getTicks(); - kernel::publishSystemEvent(kernel::SystemEvent::BootSplash); + // Give the UI some time to redraw + // If we don't do this, various init calls will read files and block SPI IO for the display + // This would result in a blank/black screen being shown during this phase of the boot process + // This works with 5 ms on a T-Lora Pager, so we give it 10 ms to be safe + kernel::delayMillis(10); setupDisplay(); // Set backlight + // This event will likely block as other systems are initialized + // e.g. Wi-Fi reads AP configs from SD card + kernel::publishSystemEvent(kernel::SystemEvent::BootSplash); + if (!setupUsbBootMode()) { initFromBootApp(); waitForMinimalSplashDuration(start_time); diff --git a/Tactility/Source/app/calculator/Calculator.cpp b/Tactility/Source/app/calculator/Calculator.cpp index e5b9a0a0..dc8f4601 100644 --- a/Tactility/Source/app/calculator/Calculator.cpp +++ b/Tactility/Source/app/calculator/Calculator.cpp @@ -168,7 +168,7 @@ class CalculatorApp : public App { lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT); - lv_obj_t* toolbar = tt::lvgl::toolbar_create(parent, context); + lv_obj_t* toolbar = lvgl::toolbar_create(parent, context); lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); lv_obj_t* wrapper = lv_obj_create(parent); @@ -209,10 +209,10 @@ class CalculatorApp : public App { lv_obj_set_style_pad_all(btnm, 5, LV_PART_MAIN); lv_obj_set_style_pad_row(btnm, 10, LV_PART_MAIN); lv_obj_set_style_pad_column(btnm, 5, LV_PART_MAIN); - lv_obj_set_style_border_width(btnm, 0, LV_PART_MAIN); + lv_obj_set_style_border_width(btnm, 2, LV_PART_MAIN); lv_obj_set_style_bg_color(btnm, lv_palette_main(LV_PALETTE_BLUE), LV_PART_ITEMS); - lv_obj_set_style_border_width(btnm, 0, LV_PART_MAIN); + // lv_obj_set_style_border_width(btnm, 0, LV_PART_MAIN); if (lv_display_get_horizontal_resolution(nullptr) <= 240 || lv_display_get_vertical_resolution(nullptr) <= 240) { //small screens lv_obj_set_size(btnm, lv_pct(100), lv_pct(60)); } else { //large screens diff --git a/Tactility/Source/app/chat/ChatApp.cpp b/Tactility/Source/app/chat/ChatApp.cpp index 726e83bb..5bd2d1ed 100644 --- a/Tactility/Source/app/chat/ChatApp.cpp +++ b/Tactility/Source/app/chat/ChatApp.cpp @@ -33,28 +33,15 @@ class ChatApp : public App { lv_obj_scroll_to_y(msg_list, lv_obj_get_scroll_y(msg_list) + 20, LV_ANIM_ON); } - static void onQuickSendClicked(lv_event_t* e) { - auto* self = static_cast(lv_event_get_user_data(e)); - auto* btn = static_cast(lv_event_get_target(e)); - const char* message = lv_label_get_text(lv_obj_get_child(btn, 0)); - - if (message) { - self->addMessage(message); - if (!service::espnow::send(BROADCAST_ADDRESS, (const uint8_t*)message, strlen(message))) { - TT_LOG_E(TAG, "Failed to send message"); - } - } - } - static void onSendClicked(lv_event_t* e) { auto* self = static_cast(lv_event_get_user_data(e)); auto* msg = lv_textarea_get_text(self->input_field); - auto msg_len = strlen(msg); + const auto msg_len = strlen(msg); if (self->msg_list && msg && msg_len) { self->addMessage(msg); - if (!service::espnow::send(BROADCAST_ADDRESS, (const uint8_t*)msg, msg_len)) { + if (!service::espnow::send(BROADCAST_ADDRESS, reinterpret_cast(msg), msg_len)) { TT_LOG_E(TAG, "Failed to send message"); } @@ -64,14 +51,14 @@ class ChatApp : public App { void onReceive(const esp_now_recv_info_t* receiveInfo, const uint8_t* data, int length) { // Append \0 to make it a string - char* buffer = (char*)malloc(length + 1); + auto buffer = static_cast(malloc(length + 1)); memcpy(buffer, data, length); buffer[length] = 0x00; - std::string message_prefixed = std::string("Received: ") + buffer; + const std::string message_prefixed = std::string("Received: ") + buffer; - tt::lvgl::getSyncLock()->lock(); + lvgl::getSyncLock()->lock(); addMessage(message_prefixed.c_str()); - tt::lvgl::getSyncLock()->unlock(); + lvgl::getSyncLock()->unlock(); free(buffer); } @@ -82,7 +69,7 @@ public: // TODO: Move this to a configuration screen/app static const uint8_t key[ESP_NOW_KEY_LEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; auto config = service::espnow::EspNowConfig( - (uint8_t*)key, + const_cast(key), service::espnow::Mode::Station, 1, false, @@ -105,58 +92,39 @@ public: } void onShow(AppContext& context, lv_obj_t* parent) override { + lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN); + lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT); - // Create toolbar - auto* toolbar = tt::lvgl::toolbar_create(parent, context); - lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0); - const int toolbar_height = lv_obj_get_height(toolbar); + lvgl::toolbar_create(parent, context); // Message list msg_list = lv_list_create(parent); - lv_obj_set_size(msg_list, lv_pct(75), lv_pct(43)); - lv_obj_align(msg_list, LV_ALIGN_TOP_LEFT, 5, toolbar_height + 45); + lv_obj_set_flex_grow(msg_list, 1); + lv_obj_set_width(msg_list, LV_PCT(100)); + lv_obj_set_flex_grow(msg_list, 1); lv_obj_set_style_bg_color(msg_list, lv_color_hex(0x262626), 0); lv_obj_set_style_border_width(msg_list, 1, 0); - lv_obj_set_style_pad_all(msg_list, 5, 0); - - // Quick message panel - auto* quick_panel = lv_obj_create(parent); - lv_obj_set_size(quick_panel, lv_pct(20), lv_pct(58)); - lv_obj_align(quick_panel, LV_ALIGN_TOP_RIGHT, -5, toolbar_height + 15); // Adjusted to match - lv_obj_set_flex_flow(quick_panel, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(quick_panel, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); - lv_obj_set_style_pad_all(quick_panel, 5, 0); - - // Quick message buttons - const char* quick_msgs[] = {":-)", "+1", ":-("}; - for (size_t i = 0; i < sizeof(quick_msgs)/sizeof(quick_msgs[0]); i++) { - lv_obj_t* btn = lv_btn_create(quick_panel); - lv_obj_set_size(btn, lv_pct(75), 25); - lv_obj_add_event_cb(btn, onQuickSendClicked, LV_EVENT_CLICKED, this); - - lv_obj_t* label = lv_label_create(btn); - lv_label_set_text(label, quick_msgs[i]); - lv_obj_center(label); - } + lv_obj_set_style_pad_ver(msg_list, 0, 0); + lv_obj_set_style_pad_hor(msg_list, 4, 0); // Input panel - auto* input_panel = lv_obj_create(parent); - lv_obj_set_size(input_panel, lv_pct(95), 60); - lv_obj_align(input_panel, LV_ALIGN_BOTTOM_MID, 0, -5); - lv_obj_set_flex_flow(input_panel, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(input_panel, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); - lv_obj_set_style_pad_all(input_panel, 5, 0); + auto* bottom_wrapper = lv_obj_create(parent); + lv_obj_set_flex_flow(bottom_wrapper, LV_FLEX_FLOW_ROW); + lv_obj_set_size(bottom_wrapper, LV_PCT(100), LV_SIZE_CONTENT); + lv_obj_set_style_pad_all(bottom_wrapper, 0, 0); + lv_obj_set_style_pad_column(bottom_wrapper, 4, 0); + lv_obj_set_style_border_opa(bottom_wrapper, 0, LV_STATE_DEFAULT); // Input field - input_field = lv_textarea_create(input_panel); + input_field = lv_textarea_create(bottom_wrapper); lv_obj_set_flex_grow(input_field, 1); - lv_obj_set_height(input_field, LV_PCT(100)); lv_textarea_set_placeholder_text(input_field, "Type a message..."); lv_textarea_set_one_line(input_field, true); // Send button - auto* send_btn = lv_btn_create(input_panel); - lv_obj_set_size(send_btn, 80, LV_PCT(100)); + auto* send_btn = lv_button_create(bottom_wrapper); + lv_obj_set_style_margin_all(send_btn, 0, LV_STATE_DEFAULT); + lv_obj_set_style_margin_top(send_btn, 2, LV_STATE_DEFAULT); // Hack to fix alignment lv_obj_add_event_cb(send_btn, onSendClicked, LV_EVENT_CLICKED, this); auto* btn_label = lv_label_create(send_btn);