Fix menu navigation issues with Bluetooth and initial focus
- Initialize menu context when showing menu to properly track focused item - Fix double-activation bug that caused immediate exit from Bluetooth menu - Add separate refresh_bt_device_list() to avoid infinite discovery loop - Delete old BT page before creating new one to prevent memory leaks - Add "Clear Paired" option to Bluetooth menu - Improve Bluetooth menu refresh behavior to show "Scanning..." message 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
289
main/gui.c
289
main/gui.c
@@ -116,6 +116,39 @@ static lv_style_t _styleFocusedBtn;
|
|||||||
|
|
||||||
static menu_context_t _menuContext;
|
static menu_context_t _menuContext;
|
||||||
|
|
||||||
|
// Hide *all* headers/back buttons that LVGL may show for this menu
|
||||||
|
static void menu_hide_headers(lv_obj_t *menu) {
|
||||||
|
if (!menu) return;
|
||||||
|
|
||||||
|
// Main header (normal menus)
|
||||||
|
lv_obj_t *mh = lv_menu_get_main_header(menu);
|
||||||
|
if (mh) {
|
||||||
|
lv_obj_add_flag(mh, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(mh, 0);
|
||||||
|
}
|
||||||
|
lv_obj_t *mh_back = lv_menu_get_main_header_back_button(menu);
|
||||||
|
if (mh_back) {
|
||||||
|
lv_obj_add_flag(mh_back, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_width(mh_back, 0);
|
||||||
|
lv_obj_set_height(mh_back, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sidebar header (if you ever use sidebar mode)
|
||||||
|
lv_obj_t *sh = lv_menu_get_sidebar_header(menu);
|
||||||
|
if (sh) {
|
||||||
|
lv_obj_add_flag(sh, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(sh, 0);
|
||||||
|
}
|
||||||
|
lv_obj_t *sh_back = lv_menu_get_sidebar_header_back_button(menu);
|
||||||
|
if (sh_back) {
|
||||||
|
lv_obj_add_flag(sh_back, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_width(sh_back, 0);
|
||||||
|
lv_obj_set_height(sh_back, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static bool notify_lvgl_flush_ready(void *user_ctx) {
|
static bool notify_lvgl_flush_ready(void *user_ctx) {
|
||||||
if (disp) {
|
if (disp) {
|
||||||
lv_display_flush_ready(disp);
|
lv_display_flush_ready(disp);
|
||||||
@@ -129,8 +162,12 @@ static lv_obj_t* create_main_page(void) {
|
|||||||
lv_obj_t* menu = create_menu_container();
|
lv_obj_t* menu = create_menu_container();
|
||||||
|
|
||||||
main_page = lv_menu_page_create(menu, NULL);
|
main_page = lv_menu_page_create(menu, NULL);
|
||||||
|
|
||||||
lv_obj_set_style_radius(main_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(main_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(main_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(main_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
|
lv_obj_set_style_pad_all(main_page, 0, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_pad_row(main_page, 0, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_pad_column(main_page, 0, LV_PART_MAIN);
|
||||||
lv_obj_set_scrollbar_mode(main_page, LV_SCROLLBAR_MODE_AUTO);
|
lv_obj_set_scrollbar_mode(main_page, LV_SCROLLBAR_MODE_AUTO);
|
||||||
lv_obj_set_size(main_page, lv_pct(100), lv_pct(100));
|
lv_obj_set_size(main_page, lv_pct(100), lv_pct(100));
|
||||||
|
|
||||||
@@ -141,7 +178,7 @@ static lv_obj_t* create_main_page(void) {
|
|||||||
|
|
||||||
addMenuItem(main_page, "Calibration");
|
addMenuItem(main_page, "Calibration");
|
||||||
addMenuItem(main_page, "Volume");
|
addMenuItem(main_page, "Volume");
|
||||||
addMenuItem(main_page, "About");
|
//addMenuItem(main_page, "About");
|
||||||
addMenuItem(main_page, "Exit");
|
addMenuItem(main_page, "Exit");
|
||||||
|
|
||||||
return main_page;
|
return main_page;
|
||||||
@@ -157,6 +194,11 @@ static void show_menu(void) {
|
|||||||
lv_menu_set_page(menu, main_page);
|
lv_menu_set_page(menu, main_page);
|
||||||
_currentPage = main_page;
|
_currentPage = main_page;
|
||||||
|
|
||||||
|
// Initialize menu context to track the focused item
|
||||||
|
currentFocusIndex(&_menuContext);
|
||||||
|
|
||||||
|
menu_hide_headers(menu);
|
||||||
|
|
||||||
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
@@ -359,6 +401,8 @@ static const char * items[] = { // your menu entries
|
|||||||
static lv_obj_t * btn_array[ITEM_COUNT];
|
static lv_obj_t * btn_array[ITEM_COUNT];
|
||||||
static int selected_idx = 0;
|
static int selected_idx = 0;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Called whenever a button is "activated" (Enter/Click)
|
// Called whenever a button is "activated" (Enter/Click)
|
||||||
static void btn_click_cb(lv_event_t * e) {
|
static void btn_click_cb(lv_event_t * e) {
|
||||||
lv_obj_t * btn = lv_event_get_target(e);
|
lv_obj_t * btn = lv_event_get_target(e);
|
||||||
@@ -487,6 +531,25 @@ static void activate_selected(void)
|
|||||||
UNLOCK();
|
UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Event handler to control label scrolling based on focus state
|
||||||
|
static void label_scroll_focus_cb(lv_event_t * e)
|
||||||
|
{
|
||||||
|
lv_event_code_t code = lv_event_get_code(e);
|
||||||
|
lv_obj_t * btn = lv_event_get_target(e);
|
||||||
|
lv_obj_t * lbl = lv_obj_get_child(btn, 0); // Get the label child
|
||||||
|
|
||||||
|
if (!lbl) return;
|
||||||
|
|
||||||
|
if (code == LV_EVENT_FOCUSED) {
|
||||||
|
// Start scrolling when focused
|
||||||
|
lv_label_set_long_mode(lbl, LV_LABEL_LONG_SCROLL_CIRCULAR);
|
||||||
|
}
|
||||||
|
else if (code == LV_EVENT_DEFOCUSED) {
|
||||||
|
// Stop scrolling and reset position when defocused
|
||||||
|
lv_label_set_long_mode(lbl, LV_LABEL_LONG_CLIP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static lv_obj_t * addMenuItem(lv_obj_t *page, const char *text)
|
static lv_obj_t * addMenuItem(lv_obj_t *page, const char *text)
|
||||||
{
|
{
|
||||||
if (!page || !text) {
|
if (!page || !text) {
|
||||||
@@ -526,10 +589,17 @@ static lv_obj_t * addMenuItem(lv_obj_t *page, const char *text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
lv_label_set_text(lbl, text);
|
lv_label_set_text(lbl, text);
|
||||||
|
lv_label_set_long_mode(lbl, LV_LABEL_LONG_CLIP); // Start with clipping, scrolling only when focused
|
||||||
|
lv_obj_set_width(lbl, LV_PCT(95)); // Set width to allow scrolling
|
||||||
lv_obj_set_style_radius(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(lbl, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
|
lv_obj_set_style_anim_time(lbl, 4000, LV_PART_MAIN); // Set scrolling duration (4 seconds per cycle - slower)
|
||||||
lv_obj_align(lbl, LV_ALIGN_LEFT_MID, 0, 0); // Center vertically, align left horizontally
|
lv_obj_align(lbl, LV_ALIGN_LEFT_MID, 0, 0); // Center vertically, align left horizontally
|
||||||
|
|
||||||
|
// Add focus event handler to control scrolling
|
||||||
|
lv_obj_add_event_cb(btn, label_scroll_focus_cb, LV_EVENT_FOCUSED, NULL);
|
||||||
|
lv_obj_add_event_cb(btn, label_scroll_focus_cb, LV_EVENT_DEFOCUSED, NULL);
|
||||||
|
|
||||||
// click callback
|
// click callback
|
||||||
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
|
lv_obj_add_event_cb(btn, btn_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
@@ -587,13 +657,41 @@ static void ensure_menu_styles(void) {
|
|||||||
|
|
||||||
static lv_obj_t* create_menu_container(void) {
|
static lv_obj_t* create_menu_container(void) {
|
||||||
if (_menu == NULL) {
|
if (_menu == NULL) {
|
||||||
|
|
||||||
|
|
||||||
_menu = lv_menu_create(lv_scr_act());
|
_menu = lv_menu_create(lv_scr_act());
|
||||||
|
|
||||||
|
menu_hide_headers(_menu);
|
||||||
|
|
||||||
lv_obj_set_style_radius(_menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(_menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(_menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(_menu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_size(_menu, lv_pct(100), lv_pct(100));
|
lv_obj_set_size(_menu, lv_pct(100), lv_pct(100));
|
||||||
lv_obj_center(_menu);
|
lv_obj_center(_menu);
|
||||||
lv_obj_set_scrollbar_mode(_menu, LV_SCROLLBAR_MODE_AUTO);
|
lv_obj_set_scrollbar_mode(_menu, LV_SCROLLBAR_MODE_AUTO);
|
||||||
lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN); // Hidden by default
|
lv_obj_add_flag(_menu, LV_OBJ_FLAG_HIDDEN); // Hidden by default
|
||||||
|
|
||||||
|
// Hide the sidebar/header
|
||||||
|
lv_menu_set_sidebar_page(_menu, NULL);
|
||||||
|
lv_obj_set_style_pad_all(_menu, 0, LV_PART_MAIN);
|
||||||
|
|
||||||
|
// Disable the back button in header
|
||||||
|
lv_menu_set_mode_root_back_button(_menu, LV_MENU_ROOT_BACK_BUTTON_DISABLED);
|
||||||
|
|
||||||
|
// Find and hide the header container
|
||||||
|
// The menu has 2 children: child 0 is header, child 1 is content area
|
||||||
|
uint32_t menu_child_count = lv_obj_get_child_count(_menu);
|
||||||
|
ESP_LOGI(TAG, "Menu container has %d children", (int)menu_child_count);
|
||||||
|
if (menu_child_count >= 1) {
|
||||||
|
lv_obj_t* header = lv_obj_get_child(_menu, 0);
|
||||||
|
int32_t h = lv_obj_get_height(header);
|
||||||
|
int32_t w = lv_obj_get_width(header);
|
||||||
|
ESP_LOGI(TAG, " Header (child 0): %p, size=%dx%d", header, (int)w, (int)h);
|
||||||
|
|
||||||
|
// Hide the header completely
|
||||||
|
lv_obj_add_flag(header, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(header, 0);
|
||||||
|
ESP_LOGI(TAG, " Hidden header");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return _menu;
|
return _menu;
|
||||||
}
|
}
|
||||||
@@ -643,8 +741,23 @@ static void bt_device_click_cb(lv_event_t * e) {
|
|||||||
return;
|
return;
|
||||||
} else if (strcmp(txt, "Refresh") == 0) {
|
} else if (strcmp(txt, "Refresh") == 0) {
|
||||||
LOCK();
|
LOCK();
|
||||||
// Use system event instead of direct BT call
|
// Recreate the BT page with discovery enabled to show "Scanning..."
|
||||||
system_requestBtRefresh();
|
show_bt_device_list();
|
||||||
|
UNLOCK();
|
||||||
|
return;
|
||||||
|
} else if (strcmp(txt, "Clear Paired") == 0) {
|
||||||
|
LOCK();
|
||||||
|
// Clear all paired devices from NVS and device list
|
||||||
|
esp_err_t ret = system_clearAllPairedDevices();
|
||||||
|
if (ret == ESP_OK) {
|
||||||
|
ESP_LOGI(TAG, "Successfully cleared all paired devices from NVS");
|
||||||
|
// Also clear the in-memory device list used by GUI
|
||||||
|
bt_clear_all_devices();
|
||||||
|
// Refresh the device list to show updated state
|
||||||
|
system_requestBtRefresh();
|
||||||
|
} else {
|
||||||
|
ESP_LOGE(TAG, "Failed to clear paired devices: %s", esp_err_to_name(ret));
|
||||||
|
}
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -676,8 +789,8 @@ static void bt_device_click_cb(lv_event_t * e) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static lv_obj_t* create_bt_device_page(void) {
|
static lv_obj_t* create_bt_device_page(bool start_discovery) {
|
||||||
ESP_LOGI(TAG, "Creating Bluetooth device page");
|
ESP_LOGI(TAG, "Creating Bluetooth device page (start_discovery=%d)", start_discovery);
|
||||||
|
|
||||||
lv_obj_t* menu = create_menu_container();
|
lv_obj_t* menu = create_menu_container();
|
||||||
if (!menu) {
|
if (!menu) {
|
||||||
@@ -685,6 +798,13 @@ static lv_obj_t* create_bt_device_page(void) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete old BT page if it exists to prevent memory leaks
|
||||||
|
if (_bt_page) {
|
||||||
|
ESP_LOGI(TAG, "Deleting old Bluetooth page");
|
||||||
|
lv_obj_del(_bt_page);
|
||||||
|
_bt_page = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
_bt_page = lv_menu_page_create(menu, NULL);
|
_bt_page = lv_menu_page_create(menu, NULL);
|
||||||
if (!_bt_page) {
|
if (!_bt_page) {
|
||||||
ESP_LOGE(TAG, "Failed to create Bluetooth page");
|
ESP_LOGE(TAG, "Failed to create Bluetooth page");
|
||||||
@@ -693,19 +813,23 @@ static lv_obj_t* create_bt_device_page(void) {
|
|||||||
|
|
||||||
lv_obj_set_style_radius(_bt_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(_bt_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(_bt_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(_bt_page, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
|
lv_obj_set_style_pad_all(_bt_page, 0, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_pad_row(_bt_page, 0, LV_PART_MAIN);
|
||||||
|
lv_obj_set_style_pad_column(_bt_page, 0, LV_PART_MAIN);
|
||||||
lv_obj_set_scrollbar_mode(_bt_page, LV_SCROLLBAR_MODE_AUTO);
|
lv_obj_set_scrollbar_mode(_bt_page, LV_SCROLLBAR_MODE_AUTO);
|
||||||
lv_obj_set_size(_bt_page, lv_pct(100), lv_pct(100));
|
lv_obj_set_size(_bt_page, lv_pct(100), lv_pct(100));
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Starting Bluetooth discovery");
|
bool discovery_started = false;
|
||||||
bool discovery_started = true;
|
if (start_discovery) {
|
||||||
#if 0
|
ESP_LOGI(TAG, "Starting Bluetooth discovery");
|
||||||
// Try to start discovery (may fail if BT stack is busy)
|
// Try to start discovery (may fail if BT stack is busy)
|
||||||
bool discovery_started = bt_start_discovery();
|
discovery_started = bt_start_discovery();
|
||||||
|
|
||||||
if (!discovery_started) {
|
if (!discovery_started) {
|
||||||
ESP_LOGW(TAG, "Discovery not started - will show paired devices only");
|
ESP_LOGW(TAG, "Discovery not started - will show paired devices only");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// Get device list
|
// Get device list
|
||||||
ESP_LOGI(TAG, "Getting device list");
|
ESP_LOGI(TAG, "Getting device list");
|
||||||
bt_device_list_t* device_list = bt_get_device_list();
|
bt_device_list_t* device_list = bt_get_device_list();
|
||||||
@@ -716,9 +840,10 @@ static lv_obj_t* create_bt_device_page(void) {
|
|||||||
|
|
||||||
if (device_list->count == 0) {
|
if (device_list->count == 0) {
|
||||||
// Show appropriate message based on discovery status
|
// Show appropriate message based on discovery status
|
||||||
const char* msg = discovery_started ? "Scanning for devices..." : "No devices found";
|
const char* msg = discovery_started ? "Scanning..." : "No devices found";
|
||||||
lv_obj_t* tmpObj = addMenuItem(_bt_page, msg);
|
lv_obj_t* tmpObj = addMenuItem(_bt_page, msg);
|
||||||
lv_obj_add_state(tmpObj, LV_STATE_DISABLED);
|
lv_obj_add_state(tmpObj, LV_STATE_DISABLED);
|
||||||
|
lv_obj_clear_state(tmpObj, LV_STATE_FOCUSED); // Remove focus from disabled item
|
||||||
} else {
|
} else {
|
||||||
// Add devices to the page
|
// Add devices to the page
|
||||||
bool first = true;
|
bool first = true;
|
||||||
@@ -738,10 +863,18 @@ static lv_obj_t* create_bt_device_page(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add back/refresh options
|
// Add back/refresh/clear options
|
||||||
lv_obj_t* refresh_btn = addMenuItem(_bt_page, "Refresh");
|
lv_obj_t* refresh_btn = addMenuItem(_bt_page, "Refresh");
|
||||||
lv_obj_add_event_cb(refresh_btn, bt_device_click_cb, LV_EVENT_CLICKED, NULL);
|
lv_obj_add_event_cb(refresh_btn, bt_device_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
|
// If no devices were listed, focus on Refresh button
|
||||||
|
if (device_list->count == 0) {
|
||||||
|
lv_obj_add_state(refresh_btn, LV_STATE_FOCUSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_t* clear_btn = addMenuItem(_bt_page, "Clear Paired");
|
||||||
|
lv_obj_add_event_cb(clear_btn, bt_device_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
lv_obj_t* back_btn = addMenuItem(_bt_page, "Back");
|
lv_obj_t* back_btn = addMenuItem(_bt_page, "Back");
|
||||||
lv_obj_add_event_cb(back_btn, bt_device_click_cb, LV_EVENT_CLICKED, NULL);
|
lv_obj_add_event_cb(back_btn, bt_device_click_cb, LV_EVENT_CLICKED, NULL);
|
||||||
|
|
||||||
@@ -749,7 +882,10 @@ static lv_obj_t* create_bt_device_page(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void show_bt_device_list(void) {
|
static void show_bt_device_list(void) {
|
||||||
ESP_LOGI(TAG, "Showing Bluetooth device list");
|
ESP_LOGI(TAG, "Showing Bluetooth device list with discovery");
|
||||||
|
|
||||||
|
// Start discovery when explicitly showing the BT device list
|
||||||
|
bool should_start_discovery = true;
|
||||||
|
|
||||||
lv_obj_t* menu = create_menu_container();
|
lv_obj_t* menu = create_menu_container();
|
||||||
if (!menu) {
|
if (!menu) {
|
||||||
@@ -757,7 +893,7 @@ static void show_bt_device_list(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lv_obj_t* bt_page = create_bt_device_page();
|
lv_obj_t* bt_page = create_bt_device_page(should_start_discovery);
|
||||||
if (!bt_page) {
|
if (!bt_page) {
|
||||||
ESP_LOGE(TAG, "Failed to create Bluetooth device page");
|
ESP_LOGE(TAG, "Failed to create Bluetooth device page");
|
||||||
return;
|
return;
|
||||||
@@ -767,12 +903,52 @@ static void show_bt_device_list(void) {
|
|||||||
_currentPage = bt_page;
|
_currentPage = bt_page;
|
||||||
_mode = GUI_MENU; // Keep in menu mode
|
_mode = GUI_MENU; // Keep in menu mode
|
||||||
|
|
||||||
|
menu_hide_headers(menu);
|
||||||
|
|
||||||
|
|
||||||
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Bluetooth device list displayed");
|
ESP_LOGI(TAG, "Bluetooth device list displayed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void refresh_bt_device_list(void) {
|
||||||
|
ESP_LOGI(TAG, "Refreshing Bluetooth device list without new discovery");
|
||||||
|
|
||||||
|
// Don't start new discovery, just refresh the display with current devices
|
||||||
|
bool should_start_discovery = false;
|
||||||
|
|
||||||
|
lv_obj_t* menu = create_menu_container();
|
||||||
|
if (!menu) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create menu container for Bluetooth list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_obj_t* bt_page = create_bt_device_page(should_start_discovery);
|
||||||
|
if (!bt_page) {
|
||||||
|
ESP_LOGE(TAG, "Failed to create Bluetooth device page");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lv_menu_set_page(menu, bt_page);
|
||||||
|
_currentPage = bt_page;
|
||||||
|
_mode = GUI_MENU; // Keep in menu mode
|
||||||
|
|
||||||
|
menu_hide_headers(menu);
|
||||||
|
|
||||||
|
|
||||||
|
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "Bluetooth device list refreshed");
|
||||||
|
}
|
||||||
|
|
||||||
// ───── VOLUME CONTROL PAGE ─────
|
// ───── VOLUME CONTROL PAGE ─────
|
||||||
static lv_obj_t* create_volume_page(void) {
|
static lv_obj_t* create_volume_page(void) {
|
||||||
ESP_LOGI(TAG, "Creating volume control page");
|
ESP_LOGI(TAG, "Creating volume control page");
|
||||||
@@ -794,6 +970,14 @@ static lv_obj_t* create_volume_page(void) {
|
|||||||
lv_obj_set_scrollbar_mode(_volume_page, LV_SCROLLBAR_MODE_OFF);
|
lv_obj_set_scrollbar_mode(_volume_page, LV_SCROLLBAR_MODE_OFF);
|
||||||
lv_obj_set_size(_volume_page, lv_pct(100), lv_pct(100));
|
lv_obj_set_size(_volume_page, lv_pct(100), lv_pct(100));
|
||||||
|
|
||||||
|
// Hide header
|
||||||
|
uint32_t child_count = lv_obj_get_child_count(_volume_page);
|
||||||
|
if (child_count >= 1) {
|
||||||
|
lv_obj_t* header = lv_obj_get_child(_volume_page, 0);
|
||||||
|
lv_obj_add_flag(header, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(header, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Create title label
|
// Create title label
|
||||||
lv_obj_t* title = lv_label_create(_volume_page);
|
lv_obj_t* title = lv_label_create(_volume_page);
|
||||||
lv_label_set_text(title, "Volume Control");
|
lv_label_set_text(title, "Volume Control");
|
||||||
@@ -857,6 +1041,8 @@ static void show_volume_control(void) {
|
|||||||
_currentPage = volume_page;
|
_currentPage = volume_page;
|
||||||
_mode = GUI_MENU; // Keep in menu mode
|
_mode = GUI_MENU; // Keep in menu mode
|
||||||
|
|
||||||
|
menu_hide_headers(menu);
|
||||||
|
|
||||||
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_remove_flag(menu, LV_OBJ_FLAG_HIDDEN);
|
||||||
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(_bubble, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
|
||||||
@@ -963,11 +1149,20 @@ static void build_scrollable_menu(void) {
|
|||||||
|
|
||||||
|
|
||||||
lv_obj_t * main = lv_menu_page_create(menu, NULL);
|
lv_obj_t * main = lv_menu_page_create(menu, NULL);
|
||||||
|
|
||||||
lv_obj_set_style_radius(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(main, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_scrollbar_mode(main, LV_SCROLLBAR_MODE_AUTO);
|
lv_obj_set_scrollbar_mode(main, LV_SCROLLBAR_MODE_AUTO);
|
||||||
lv_obj_set_size(main, lv_pct(100), lv_pct(100));
|
lv_obj_set_size(main, lv_pct(100), lv_pct(100));
|
||||||
|
|
||||||
|
// Hide header
|
||||||
|
uint32_t child_count = lv_obj_get_child_count(main);
|
||||||
|
if (child_count >= 1) {
|
||||||
|
lv_obj_t* header = lv_obj_get_child(main, 0);
|
||||||
|
lv_obj_add_flag(header, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(header, 0);
|
||||||
|
}
|
||||||
|
|
||||||
lv_menu_set_page(menu, main);
|
lv_menu_set_page(menu, main);
|
||||||
|
|
||||||
lv_obj_t * tmpObj;
|
lv_obj_t * tmpObj;
|
||||||
@@ -975,10 +1170,19 @@ static void build_scrollable_menu(void) {
|
|||||||
|
|
||||||
|
|
||||||
lv_obj_t * calMenu = lv_menu_page_create(menu, NULL);
|
lv_obj_t * calMenu = lv_menu_page_create(menu, NULL);
|
||||||
|
|
||||||
lv_obj_set_style_radius(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_radius(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_style_border_width(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
lv_obj_set_style_border_width(calMenu, 0, LV_PART_MAIN | LV_STATE_ANY);
|
||||||
lv_obj_set_scrollbar_mode(calMenu, LV_SCROLLBAR_MODE_AUTO);
|
lv_obj_set_scrollbar_mode(calMenu, LV_SCROLLBAR_MODE_AUTO);
|
||||||
|
|
||||||
|
// Hide header
|
||||||
|
child_count = lv_obj_get_child_count(calMenu);
|
||||||
|
if (child_count >= 1) {
|
||||||
|
lv_obj_t* header = lv_obj_get_child(calMenu, 0);
|
||||||
|
lv_obj_add_flag(header, LV_OBJ_FLAG_HIDDEN);
|
||||||
|
lv_obj_set_height(header, 0);
|
||||||
|
}
|
||||||
|
|
||||||
tmpObj = addMenuItem(main, "Bluetooth");
|
tmpObj = addMenuItem(main, "Bluetooth");
|
||||||
lv_obj_add_state(tmpObj, LV_STATE_FOCUSED);
|
lv_obj_add_state(tmpObj, LV_STATE_FOCUSED);
|
||||||
//lv_obj_add_flag(tmpObj, LV_OBJ_FLAG_USER_1);
|
//lv_obj_add_flag(tmpObj, LV_OBJ_FLAG_USER_1);
|
||||||
@@ -1056,7 +1260,7 @@ static void gui_task(void *pvParameters)
|
|||||||
system_requestVolumeUp();
|
system_requestVolumeUp();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
menuNext();
|
menuPrevious();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "MAIN: Button UP SHORT");
|
ESP_LOGI(TAG, "MAIN: Button UP SHORT");
|
||||||
@@ -1076,7 +1280,7 @@ static void gui_task(void *pvParameters)
|
|||||||
system_requestVolumeDown();
|
system_requestVolumeDown();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
menuPrevious();
|
menuNext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "MAIN: Button DOWN SHORT");
|
ESP_LOGI(TAG, "MAIN: Button DOWN SHORT");
|
||||||
@@ -1095,19 +1299,15 @@ static void gui_task(void *pvParameters)
|
|||||||
else if (_mode == GUI_MENU)
|
else if (_mode == GUI_MENU)
|
||||||
{
|
{
|
||||||
activate_selected();
|
activate_selected();
|
||||||
|
// After activation, check if we should stay in menu or exit
|
||||||
// Check if we're in special pages - don't auto-exit
|
// (activation may have changed _currentPage or _mode)
|
||||||
if (_currentPage == _bt_page) {
|
if (_mode == GUI_BUBBLE) {
|
||||||
// Don't automatically exit to bubble mode from Bluetooth page
|
// Already handled by the menu item (e.g., "Exit" was selected)
|
||||||
} else if (_currentPage == _volume_page) {
|
} else if (_currentPage == _bt_page || _currentPage == _volume_page) {
|
||||||
// Don't automatically exit to bubble mode from Volume page
|
// Stay in menu mode on these pages
|
||||||
} else {
|
|
||||||
ESP_LOGI(TAG, "return to main");
|
|
||||||
// In main menu - activate selection and exit to bubble
|
|
||||||
activate_selected();
|
|
||||||
_mode = GUI_BUBBLE;
|
|
||||||
show_bubble(); // Cleanup menu and show bubble
|
|
||||||
}
|
}
|
||||||
|
// Note: For main menu items that navigate to subpages,
|
||||||
|
// the btn_click_cb handles the navigation and keeps _mode = GUI_MENU
|
||||||
}
|
}
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
ESP_LOGI(TAG, "MAIN: Button 0 LONG - Exit");
|
ESP_LOGI(TAG, "MAIN: Button 0 LONG - Exit");
|
||||||
@@ -1136,16 +1336,27 @@ static void gui_task(void *pvParameters)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Check for system events
|
||||||
|
uint32_t notifiedBits = 0;
|
||||||
|
xTaskNotifyWait(
|
||||||
|
0, // don't clear on entry
|
||||||
|
0xFFFFFFFF, // clear bits on exit
|
||||||
|
¬ifiedBits,
|
||||||
|
pdMS_TO_TICKS(10));
|
||||||
|
|
||||||
|
if (notifiedBits & EM_EVENT_BT_DISCOVERY_COMPLETE) {
|
||||||
|
// Discovery completed - refresh the BT page if we're on it
|
||||||
|
if (_mode == GUI_MENU && _currentPage == _bt_page) {
|
||||||
|
ESP_LOGI(TAG, "Discovery complete, refreshing Bluetooth page");
|
||||||
|
LOCK();
|
||||||
|
// Recreate the BT page with updated device list (without starting new discovery)
|
||||||
|
refresh_bt_device_list();
|
||||||
|
UNLOCK();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_mode == GUI_BUBBLE)
|
if (_mode == GUI_BUBBLE)
|
||||||
{
|
{
|
||||||
uint32_t notifiedBits = 0;
|
|
||||||
// clear on entry (first param), wait for any bit, block forever
|
|
||||||
xTaskNotifyWait(
|
|
||||||
0xFFFFFFFF, // clear any old bits on entry
|
|
||||||
0xFFFFFFFF, // clear bits on exit
|
|
||||||
¬ifiedBits,
|
|
||||||
pdMS_TO_TICKS(100));
|
|
||||||
|
|
||||||
if (notifiedBits & EM_EVENT_NEW_DATA)
|
if (notifiedBits & EM_EVENT_NEW_DATA)
|
||||||
{
|
{
|
||||||
ImuData_t d = system_getImuData();
|
ImuData_t d = system_getImuData();
|
||||||
|
|||||||
Reference in New Issue
Block a user