// 按键导航管理器 // 根据当前界面上下文分发BOOT/KEY2的单击/双击/长按事件 // 所有iot_button回调在esp_timer中执行,耗时操作通过xTaskCreate派发 #include "key_nav.h" #include "button.h" #include "sleep_mgr.h" #include "ble.h" #include "ble_transfer.h" #include "pages.h" #include "esp_log.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "ui/ui.h" #include "ui/screens/ui_ScreenHome.h" #include "ui/screens/ui_ScreenImg.h" #include "ui/screens/ui_ScreenPeiwang.h" #include "ui/screens/ui_ScreenUpdate.h" #include "ui/screens/ui_ScreenImageShar.h" #include "ui/screens/ui_ScreenImageReception.h" #include "ui/screens/ui_ScreenSharing.h" #include "ui/screens/ui_ScreenReceiving.h" #include "esp_lvgl_port.h" #include "ui/battery_ui.h" static const char *TAG = "KEY_NAV"; static nav_context_t current_ctx = NAV_CTX_HOME; void key_nav_set_context(nav_context_t ctx) { current_ctx = ctx; ESP_LOGI(TAG, "导航上下文切换: %d", ctx); } nav_context_t key_nav_get_context(void) { return current_ctx; } // === 界面切换辅助(需要LVGL锁) === static void nav_switch_screen(lv_obj_t **screen, void (*init_func)(void), nav_context_t new_ctx) { if (lvgl_port_lock(100)) { _ui_screen_change(screen, LV_SCR_LOAD_ANIM_NONE, 0, 0, init_func); lvgl_port_unlock(); } key_nav_set_context(new_ctx); } // === BOOT按键处理任务 === static void handle_boot_click_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_HOME: // Home界面BOOT单击 → Img界面 nav_switch_screen(&ui_ScreenImg, &ui_ScreenImg_screen_init, NAV_CTX_IMG); break; case NAV_CTX_IMG: // Img界面BOOT单击 → 下一张图片 if (lvgl_port_lock(100)) { for (int try = 0; try < 10; try++) { const char *next_img = get_next_image(); if (!next_img) break; if (update_ui_ImgBle(next_img)) break; ESP_LOGW(TAG, "跳过无效图片,继续下一张"); } battery_ui_show_briefly(); lvgl_port_unlock(); } break; case NAV_CTX_IMG_DELETE: // 第一次按BOOT → 显示白色边框进入二次确认 if (lvgl_port_lock(100)) { ui_ScreenImg_show_delete_confirm_border(); lvgl_port_unlock(); } key_nav_set_context(NAV_CTX_IMG_DELETE_CONFIRM); break; case NAV_CTX_IMG_DELETE_CONFIRM: // 第二次按BOOT → 执行删除 if (lvgl_port_lock(100)) { if (delete_current_image()) { ui_ScreenImg_hide_delete_container(); const char *next_img = get_current_image(); if (next_img) { update_ui_ImgBle(next_img); } } else { ui_ScreenImg_hide_delete_container(); } lvgl_port_unlock(); } key_nav_set_context(NAV_CTX_IMG); break; case NAV_CTX_PEIWANG: // 配对界面任意键 → 关蓝牙返回Home ble_stop(); nav_switch_screen(&ui_ScreenHome, &ui_ScreenHome_screen_init, NAV_CTX_HOME); break; case NAV_CTX_IMAGE_SHAR: case NAV_CTX_IMAGE_RECEPTION: // 等待配对界面任意键 → 取消传输 + 返回Home ble_transfer_cancel(); nav_switch_screen(&ui_ScreenHome, &ui_ScreenHome_screen_init, NAV_CTX_HOME); break; case NAV_CTX_UPDATE: case NAV_CTX_SHARING: case NAV_CTX_RECEIVING: // 这些界面暂不响应BOOT单击(等待自动跳转) break; } vTaskDelete(NULL); } static void handle_boot_double_click_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_IMG: // Img界面BOOT双击 → 上一张图片 if (lvgl_port_lock(100)) { for (int try = 0; try < 10; try++) { const char *prev_img = get_prev_image(); if (!prev_img) break; if (update_ui_ImgBle(prev_img)) break; ESP_LOGW(TAG, "跳过无效图片,继续上一张"); } battery_ui_show_briefly(); lvgl_port_unlock(); } break; default: break; } vTaskDelete(NULL); } static void handle_boot_long_press_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_IMG: // Img界面BOOT长按 → 显示删除确认 if (lvgl_port_lock(100)) { ui_ScreenImg_show_delete_container(); lvgl_port_unlock(); } key_nav_set_context(NAV_CTX_IMG_DELETE); break; default: break; } vTaskDelete(NULL); } // === KEY2按键处理任务 === static void handle_key2_click_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_HOME: // Home界面KEY2单击 → 开蓝牙 + 配对界面 ble_start(); nav_switch_screen(&ui_ScreenPeiwang, &ui_ScreenPeiwang_screen_init, NAV_CTX_PEIWANG); break; case NAV_CTX_IMG: // Img界面KEY2单击 → 返回Home if (lvgl_port_lock(100)) { ui_ScreenImg_hide_delete_container(); lvgl_port_unlock(); } nav_switch_screen(&ui_ScreenHome, &ui_ScreenHome_screen_init, NAV_CTX_HOME); break; case NAV_CTX_IMG_DELETE: case NAV_CTX_IMG_DELETE_CONFIRM: // 删除确认/二次确认 KEY2单击 → 取消 if (lvgl_port_lock(100)) { ui_ScreenImg_hide_delete_container(); lvgl_port_unlock(); } key_nav_set_context(NAV_CTX_IMG); break; case NAV_CTX_PEIWANG: // 配对界面KEY2单击 → 关蓝牙返回Home ble_stop(); nav_switch_screen(&ui_ScreenHome, &ui_ScreenHome_screen_init, NAV_CTX_HOME); break; case NAV_CTX_IMAGE_SHAR: case NAV_CTX_IMAGE_RECEPTION: // 等待配对界面KEY2单击 → 取消传输 + 返回Home ble_transfer_cancel(); nav_switch_screen(&ui_ScreenHome, &ui_ScreenHome_screen_init, NAV_CTX_HOME); break; default: break; } vTaskDelete(NULL); } static void handle_key2_double_click_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_HOME: case NAV_CTX_IMG: // KEY2双击 → 接收方等待配对界面 + 启动接收模式 nav_switch_screen(&ui_ScreenImageReception, &ui_ScreenImageReception_screen_init, NAV_CTX_IMAGE_RECEPTION); ble_transfer_start_receive(); break; default: break; } vTaskDelete(NULL); } static void handle_key2_long_press_task(void *arg) { if (sleep_mgr_is_screen_off()) { sleep_mgr_notify_activity(); vTaskDelete(NULL); return; } sleep_mgr_notify_activity(); switch (current_ctx) { case NAV_CTX_HOME: // Home界面KEY2长按 → 初始化图片列表 + 直接进分享等待(不闪现Img界面) init_spiffs_image_list(); nav_switch_screen(&ui_ScreenImageShar, &ui_ScreenImageShar_screen_init, NAV_CTX_IMAGE_SHAR); ble_transfer_start_send(); break; case NAV_CTX_IMG: // Img界面KEY2长按 → 发送方等待配对(分享当前图片)+ 启动发送模式 nav_switch_screen(&ui_ScreenImageShar, &ui_ScreenImageShar_screen_init, NAV_CTX_IMAGE_SHAR); ble_transfer_start_send(); break; default: break; } vTaskDelete(NULL); } // === iot_button回调(在esp_timer中执行,派发到独立任务) === static void boot_click_cb(void *arg, void *data) { xTaskCreate(handle_boot_click_task, "nav_bc", 3072, NULL, 5, NULL); } static void boot_double_click_cb(void *arg, void *data) { xTaskCreate(handle_boot_double_click_task, "nav_bd", 3072, NULL, 5, NULL); } static void boot_long_press_cb(void *arg, void *data) { xTaskCreate(handle_boot_long_press_task, "nav_bl", 3072, NULL, 5, NULL); } static void key2_click_cb(void *arg, void *data) { xTaskCreate(handle_key2_click_task, "nav_kc", 3072, NULL, 5, NULL); } static void key2_double_click_cb(void *arg, void *data) { xTaskCreate(handle_key2_double_click_task, "nav_kd", 3072, NULL, 5, NULL); } static void key2_long_press_cb(void *arg, void *data) { xTaskCreate(handle_key2_long_press_task, "nav_kl", 3072, NULL, 5, NULL); } void key_nav_init(void) { // 注册BOOT按键事件 button_on_boot_click(boot_click_cb, NULL); button_on_boot_double_click(boot_double_click_cb, NULL); button_on_boot_long_press(boot_long_press_cb, NULL); // 注册KEY2按键事件 button_on_key2_click(key2_click_cb, NULL); button_on_key2_double_click(key2_double_click_cb, NULL); button_on_key2_long_press(key2_long_press_cb, NULL); key_nav_set_context(NAV_CTX_HOME); ESP_LOGI(TAG, "按键导航初始化完成"); }