From 5eb96204681f4dbfa30ec9871ea074445579b105 Mon Sep 17 00:00:00 2001 From: Adolfo Reyna Date: Wed, 1 Jul 2026 22:51:23 -0400 Subject: [PATCH] feat(reynabot): Show dedicated speaker selection screen on launch --- Apps/ReynaBot/main/Source/main.c | 148 +++++++++++++++++++------------ 1 file changed, 92 insertions(+), 56 deletions(-) diff --git a/Apps/ReynaBot/main/Source/main.c b/Apps/ReynaBot/main/Source/main.c index 717a3f3..58768f0 100644 --- a/Apps/ReynaBot/main/Source/main.c +++ b/Apps/ReynaBot/main/Source/main.c @@ -50,6 +50,10 @@ typedef struct { lv_obj_t* btn_grace; lv_obj_t* btn_elias; + bool speaker_selected; + lv_obj_t* speaker_select_cont; + lv_obj_t* app_main_cont; + // PTT control bool is_pressed; bool start_session; @@ -281,30 +285,21 @@ static void speaker_event_cb(lv_event_t* e) { lv_obj_t* target = lv_event_get_target(e); lv_event_code_t code = lv_event_get_code(e); - if (code == LV_EVENT_CLICKED) { + if (code == LV_EVENT_CLICKED && !ctx->speaker_selected) { if (target == ctx->btn_grace) { strcpy(ctx->device_id, "grace-esp32"); - // Grace active styling - lv_obj_set_style_bg_color(ctx->btn_grace, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_grace, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_grace, lv_color_hex(0xFFFFFF), LV_PART_MAIN); - - // Elias inactive styling - lv_obj_set_style_bg_color(ctx->btn_elias, lv_color_hex(0x1C1B22), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_elias, lv_color_hex(0x2D2B36), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_elias, lv_color_hex(0x9E9E9E), LV_PART_MAIN); } else if (target == ctx->btn_elias) { strcpy(ctx->device_id, "elias-esp32"); - // Elias active styling - lv_obj_set_style_bg_color(ctx->btn_elias, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_elias, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_elias, lv_color_hex(0xFFFFFF), LV_PART_MAIN); - - // Grace inactive styling - lv_obj_set_style_bg_color(ctx->btn_grace, lv_color_hex(0x1C1B22), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_grace, lv_color_hex(0x2D2B36), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_grace, lv_color_hex(0x9E9E9E), LV_PART_MAIN); } + + ctx->speaker_selected = true; + + // Hide selection screen, show main screen + lv_obj_add_flag(ctx->speaker_select_cont, LV_OBJ_FLAG_HIDDEN); + lv_obj_remove_flag(ctx->app_main_cont, LV_OBJ_FLAG_HIDDEN); + + // Trigger UI update to refresh status and PTT button + ctx->ui_update_pending = true; } } @@ -315,7 +310,7 @@ static void ptt_event_cb(lv_event_t* e) { if (code == LV_EVENT_PRESSED) { ctx->is_pressed = true; - if (ctx->state == STATE_IDLE || ctx->state == STATE_ERROR) { + if (ctx->state == STATE_IDLE || ctx->state == ERROR_NONE) { ctx->start_session = true; } } else if (code == LV_EVENT_RELEASED || code == LV_EVENT_PRESS_LOST) { @@ -338,6 +333,13 @@ static void update_ui(ReynaBotCtx* ctx) { return; } + if (!ctx->speaker_selected) { + lv_label_set_text(ctx->lbl_status, "Choose Speaker"); + lv_obj_set_style_text_color(ctx->lbl_status, lv_color_hex(0x9E9E9E), LV_PART_MAIN); + tt_lvgl_unlock(); + return; + } + switch (ctx->state) { case STATE_IDLE: lv_label_set_text(ctx->lbl_status, "Ready"); @@ -633,60 +635,94 @@ static void on_show(AppHandle app, void* data, lv_obj_t* parent) { lv_obj_align(ctx->lbl_status, LV_ALIGN_RIGHT_MID, -10, 0); lv_obj_set_style_text_color(ctx->lbl_status, lv_color_hex(0x9E9E9E), LV_PART_MAIN); + // Initial state + ctx->speaker_selected = false; + // Default to Grace if device_id is not already configured to elias-esp32 if (strcmp(ctx->device_id, "elias-esp32") != 0) { strcpy(ctx->device_id, "grace-esp32"); } - // Speaker Selection Container (Grace / Elias) - lv_obj_t* speaker_row = lv_obj_create(parent); - lv_obj_set_size(speaker_row, lv_pct(95), 45); + // 1. Speaker Selection Container (Startup Screen) + ctx->speaker_select_cont = lv_obj_create(parent); + lv_obj_set_width(ctx->speaker_select_cont, lv_pct(95)); + lv_obj_set_flex_grow(ctx->speaker_select_cont, 1); + lv_obj_set_flex_flow(ctx->speaker_select_cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(ctx->speaker_select_cont, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(ctx->speaker_select_cont, 0, LV_PART_MAIN); + lv_obj_set_style_bg_opa(ctx->speaker_select_cont, 0, LV_PART_MAIN); + lv_obj_set_style_border_width(ctx->speaker_select_cont, 0, LV_PART_MAIN); + lv_obj_set_style_pad_row(ctx->speaker_select_cont, 16, LV_PART_MAIN); + + // Title Prompt + lv_obj_t* prompt_lbl = lv_label_create(ctx->speaker_select_cont); + lv_label_set_text(prompt_lbl, "Who is speaking?"); + lv_obj_set_style_text_color(prompt_lbl, lv_color_hex(0xFFFFFF), LV_PART_MAIN); + + // Row of two selection buttons + lv_obj_t* speaker_row = lv_obj_create(ctx->speaker_select_cont); + lv_obj_set_size(speaker_row, lv_pct(100), 140); lv_obj_set_flex_flow(speaker_row, LV_FLEX_FLOW_ROW); lv_obj_set_flex_align(speaker_row, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); lv_obj_set_style_pad_all(speaker_row, 0, LV_PART_MAIN); lv_obj_set_style_bg_opa(speaker_row, 0, LV_PART_MAIN); lv_obj_set_style_border_width(speaker_row, 0, LV_PART_MAIN); - + + // Grace Button (Girl) ctx->btn_grace = lv_btn_create(speaker_row); - lv_obj_set_size(ctx->btn_grace, lv_pct(47), 35); - lv_obj_set_style_radius(ctx->btn_grace, 8, LV_PART_MAIN); + lv_obj_set_size(ctx->btn_grace, lv_pct(46), 130); + lv_obj_set_flex_flow(ctx->btn_grace, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(ctx->btn_grace, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(ctx->btn_grace, 8, LV_PART_MAIN); + lv_obj_set_style_pad_row(ctx->btn_grace, 8, LV_PART_MAIN); + lv_obj_set_style_radius(ctx->btn_grace, 12, LV_PART_MAIN); + lv_obj_set_style_bg_color(ctx->btn_grace, lv_color_hex(0x1C1B22), LV_PART_MAIN); lv_obj_set_style_border_width(ctx->btn_grace, 1, LV_PART_MAIN); + lv_obj_set_style_border_color(ctx->btn_grace, lv_color_hex(0x2D2B36), LV_PART_MAIN); + lv_obj_add_event_cb(ctx->btn_grace, speaker_event_cb, LV_EVENT_CLICKED, ctx); + + lv_obj_t* icon_grace = lv_label_create(ctx->btn_grace); + lv_label_set_text(icon_grace, "🚺"); + lv_obj_t* lbl_grace = lv_label_create(ctx->btn_grace); lv_label_set_text(lbl_grace, "Grace"); - lv_obj_center(lbl_grace); - lv_obj_add_event_cb(ctx->btn_grace, speaker_event_cb, LV_EVENT_CLICKED, ctx); - + lv_obj_set_style_text_color(lbl_grace, lv_color_hex(0xFFFFFF), LV_PART_MAIN); + + // Elias Button (Boy) ctx->btn_elias = lv_btn_create(speaker_row); - lv_obj_set_size(ctx->btn_elias, lv_pct(47), 35); - lv_obj_set_style_radius(ctx->btn_elias, 8, LV_PART_MAIN); + lv_obj_set_size(ctx->btn_elias, lv_pct(46), 130); + lv_obj_set_flex_flow(ctx->btn_elias, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(ctx->btn_elias, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(ctx->btn_elias, 8, LV_PART_MAIN); + lv_obj_set_style_pad_row(ctx->btn_elias, 8, LV_PART_MAIN); + lv_obj_set_style_radius(ctx->btn_elias, 12, LV_PART_MAIN); + lv_obj_set_style_bg_color(ctx->btn_elias, lv_color_hex(0x1C1B22), LV_PART_MAIN); lv_obj_set_style_border_width(ctx->btn_elias, 1, LV_PART_MAIN); + lv_obj_set_style_border_color(ctx->btn_elias, lv_color_hex(0x2D2B36), LV_PART_MAIN); + lv_obj_add_event_cb(ctx->btn_elias, speaker_event_cb, LV_EVENT_CLICKED, ctx); + + lv_obj_t* icon_elias = lv_label_create(ctx->btn_elias); + lv_label_set_text(icon_elias, "🚹"); + lv_obj_t* lbl_elias = lv_label_create(ctx->btn_elias); lv_label_set_text(lbl_elias, "Elias"); - lv_obj_center(lbl_elias); - lv_obj_add_event_cb(ctx->btn_elias, speaker_event_cb, LV_EVENT_CLICKED, ctx); - - // Set initial highlights and text colors - if (strcmp(ctx->device_id, "elias-esp32") == 0) { - lv_obj_set_style_bg_color(ctx->btn_elias, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_elias, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_elias, lv_color_hex(0xFFFFFF), LV_PART_MAIN); - - lv_obj_set_style_bg_color(ctx->btn_grace, lv_color_hex(0x1C1B22), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_grace, lv_color_hex(0x2D2B36), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_grace, lv_color_hex(0x9E9E9E), LV_PART_MAIN); - } else { - lv_obj_set_style_bg_color(ctx->btn_grace, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_grace, lv_color_hex(0x6200EE), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_grace, lv_color_hex(0xFFFFFF), LV_PART_MAIN); - - lv_obj_set_style_bg_color(ctx->btn_elias, lv_color_hex(0x1C1B22), LV_PART_MAIN); - lv_obj_set_style_border_color(ctx->btn_elias, lv_color_hex(0x2D2B36), LV_PART_MAIN); - lv_obj_set_style_text_color(ctx->btn_elias, lv_color_hex(0x9E9E9E), LV_PART_MAIN); - } - + lv_obj_set_style_text_color(lbl_elias, lv_color_hex(0xFFFFFF), LV_PART_MAIN); + + // 2. Main App Container (Usual App Screen) + ctx->app_main_cont = lv_obj_create(parent); + lv_obj_set_width(ctx->app_main_cont, lv_pct(95)); + lv_obj_set_flex_grow(ctx->app_main_cont, 1); + lv_obj_set_flex_flow(ctx->app_main_cont, LV_FLEX_FLOW_COLUMN); + lv_obj_set_flex_align(ctx->app_main_cont, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER); + lv_obj_set_style_pad_all(ctx->app_main_cont, 0, LV_PART_MAIN); + lv_obj_set_style_pad_row(ctx->app_main_cont, 12, LV_PART_MAIN); + lv_obj_set_style_bg_opa(ctx->app_main_cont, 0, LV_PART_MAIN); + lv_obj_set_style_border_width(ctx->app_main_cont, 0, LV_PART_MAIN); + lv_obj_add_flag(ctx->app_main_cont, LV_OBJ_FLAG_HIDDEN); // Hidden by default + // Conversation bubble container - lv_obj_t* conv_card = lv_obj_create(parent); - lv_obj_set_width(conv_card, lv_pct(95)); + lv_obj_t* conv_card = lv_obj_create(ctx->app_main_cont); + lv_obj_set_width(conv_card, lv_pct(100)); lv_obj_set_flex_grow(conv_card, 1); lv_obj_set_flex_flow(conv_card, LV_FLEX_FLOW_COLUMN); lv_obj_set_flex_align(conv_card, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START); @@ -728,7 +764,7 @@ static void on_show(AppHandle app, void* data, lv_obj_t* parent) { lv_obj_set_style_text_color(ctx->lbl_response, lv_color_hex(0xE0E0E0), LV_PART_MAIN); // Push-to-Talk Button - ctx->btn_ptt = lv_btn_create(parent); + ctx->btn_ptt = lv_btn_create(ctx->app_main_cont); lv_obj_set_size(ctx->btn_ptt, 180, 50); lv_obj_set_style_radius(ctx->btn_ptt, 25, LV_PART_MAIN); lv_obj_set_style_bg_color(ctx->btn_ptt, lv_color_hex(0x6200EE), LV_PART_MAIN);