## 新增功能 - 图片删除:支持从 SPIFFS 彻底删除图片(物理删除 + 内存管理) - ContainerDle 管理:新增半透明圆形删除容器(含删除和返回按钮) - 状态管理:标志位模式管理 UI 状态,离开界面自动清理 ## 解决的关键问题 1. 开机闪烁 (⭐️⭐️⭐️⭐️⭐️) - 原因:LCD GRAM 保留旧数据 - 方案:背光使能前清空 GRAM(DMA 分批填充黑色,34ms) 2. 低功耗唤醒闪烁 (⭐️⭐️⭐️⭐️⭐️) - 原因:先恢复亮度后切换界面,看到旧界面 - 方案:先切换界面(背光=0)→ 延时 100ms → 恢复亮度 3. ContainerDle 状态保留 (⭐️⭐️⭐️⭐️) - 原因:LVGL 对象不销毁,状态被保留 - 方案:离开界面时主动清理(手势/按键回调中调用隐藏函数) 4. 按键回调冲突 (⭐️⭐️⭐️⭐️) - 原因:按键系统单回调限制 - 方案:统一在 main.c 管理 BOOT 按键,其他模块通过接口调用 5. 开机加载图片闪烁 (⭐️⭐️⭐️) - 原因:screen_init() 中 JPEG 解码触发渲染 - 方案:延迟到 LV_EVENT_SCREEN_LOADED 事件加载 ## 功能改动 - BOOT 按键增强:唤醒 + 退出手电筒 + 隐藏容器 + 返回 Home - 图片界面优化:支持删除当前图片并自动显示下一张 - 休眠管理优化:移除 BOOT 注册,避免回调冲突 ## 技术优化 - 资源节约:分批处理大数据(LCD GRAM 清除) - 时序优化:根据屏幕状态智能调整唤醒时序 - 模块化设计:按键集中管理 + 接口清晰 + 状态标志模式 ## 文件变更 - lcd/lcd.c: LCD GRAM 清除逻辑 - main.c: BOOT 按键统一管理 - pages/pages.c: 图片删除功能实现 - ui/screens/ui_ScreenImg.c: ContainerDle 管理 + 状态控制 - sleep_mgr/sleep_mgr.c: 按键回调优化 - ui/images: 新增删除和返回按钮图标 (s13.png, s14.png) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
219 lines
8.1 KiB
C
219 lines
8.1 KiB
C
// This file was generated by SquareLine Studio
|
||
// SquareLine Studio version: SquareLine Studio 1.6.0
|
||
// LVGL version: 8.3.11
|
||
// Project name: Lcd_Pro
|
||
|
||
#include "../ui.h"
|
||
#include "ui_ScreenSet.h" // 引入ScreenSet的函数声明
|
||
#include "../../pages/include/pages.h" // 引入图片管理函数
|
||
#include "esp_log.h" // 用于日志输出
|
||
|
||
extern void init_spiffs_image_list(void);
|
||
extern void update_ui_ImgBle(const char *img_name);
|
||
extern void free_spiffs_image_list(void);
|
||
extern const char* get_next_image(void);
|
||
extern const char* get_prev_image(void);
|
||
|
||
lv_obj_t *ui_ScreenImg = NULL;
|
||
lv_obj_t *ui_ImgBle = NULL;
|
||
lv_obj_t *ui_ContainerDle = NULL;
|
||
lv_obj_t *ui_ImageDel = NULL;
|
||
lv_obj_t *ui_ImageReturn = NULL;
|
||
|
||
// 标志:是否首次加载
|
||
static bool first_load = true;
|
||
// 标志:是否需要显示 ContainerDle(只有从 ScreenSet 点击 ImgDelete 时才为 true)
|
||
static bool should_show_container = false;
|
||
|
||
// 显示 ContainerDle
|
||
void ui_ScreenImg_show_delete_container(void) {
|
||
should_show_container = true; // 设置标志,表示需要显示
|
||
if (ui_ContainerDle) {
|
||
lv_obj_clear_flag(ui_ContainerDle, LV_OBJ_FLAG_HIDDEN);
|
||
}
|
||
}
|
||
|
||
// 隐藏 ContainerDle
|
||
void ui_ScreenImg_hide_delete_container(void) {
|
||
should_show_container = false; // 清除标志
|
||
if (ui_ContainerDle) {
|
||
lv_obj_add_flag(ui_ContainerDle, LV_OBJ_FLAG_HIDDEN);
|
||
}
|
||
}
|
||
|
||
// ImageReturn 点击事件:隐藏容器
|
||
void ui_event_ImageReturn(lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
if (event_code == LV_EVENT_CLICKED) {
|
||
ui_ScreenImg_hide_delete_container();
|
||
}
|
||
}
|
||
|
||
// ImageDel 点击事件:删除当前图片
|
||
void ui_event_ImageDel(lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
if (event_code == LV_EVENT_CLICKED) {
|
||
// 删除当前图片
|
||
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 {
|
||
// 没有图片了,可以显示提示信息
|
||
// 这里暂不处理,保持当前界面
|
||
}
|
||
} else {
|
||
// 删除失败,仍然隐藏容器
|
||
ui_ScreenImg_hide_delete_container();
|
||
}
|
||
}
|
||
}
|
||
|
||
// event funtions
|
||
void ui_event_ScreenImg( lv_event_t * e) {
|
||
lv_event_code_t event_code = lv_event_get_code(e);
|
||
|
||
// 界面加载完成事件:首次进入时才初始化图片
|
||
if ( event_code == LV_EVENT_SCREEN_LOADED ) {
|
||
if (first_load) {
|
||
first_load = false;
|
||
|
||
// 初始化图片列表
|
||
init_spiffs_image_list();
|
||
|
||
// 获取第一张可用图片
|
||
const char *first_img = get_current_image();
|
||
if (first_img) {
|
||
// 显示第一张SPIFFS图片
|
||
update_ui_ImgBle(first_img);
|
||
} else {
|
||
// 没有图片,保持显示UI资源图片 ui_img_s1_png
|
||
ESP_LOGI("ScreenImg", "SPIFFS无可用图片,显示默认UI图片");
|
||
}
|
||
}
|
||
|
||
// 每次加载界面时检查是否需要显示 ContainerDle
|
||
// 只有从 ScreenSet 点击 ImgDelete 时 should_show_container 才为 true
|
||
if (should_show_container) {
|
||
// 需要显示,保持显示状态(已在 ui_ScreenImg_show_delete_container 中显示)
|
||
should_show_container = false; // 清除标志(下次进入默认不显示)
|
||
} else {
|
||
// 不需要显示,确保隐藏
|
||
ui_ScreenImg_hide_delete_container();
|
||
}
|
||
}
|
||
|
||
if ( event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_get_act()) == LV_DIR_TOP ) {
|
||
lv_indev_wait_release(lv_indev_get_act());
|
||
// 离开界面前隐藏容器
|
||
ui_ScreenImg_hide_delete_container();
|
||
_ui_screen_change( &ui_ScreenHome, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenHome_screen_init);
|
||
}
|
||
if ( event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_get_act()) == LV_DIR_BOTTOM ) {
|
||
lv_indev_wait_release(lv_indev_get_act());
|
||
// 离开界面前隐藏容器
|
||
ui_ScreenImg_hide_delete_container();
|
||
// 设置返回到Img界面
|
||
ui_ScreenSet_set_previous(&ui_ScreenImg, &ui_ScreenImg_screen_init);
|
||
_ui_screen_change( &ui_ScreenSet, LV_SCR_LOAD_ANIM_NONE, 0, 0, &ui_ScreenSet_screen_init);
|
||
}
|
||
if ( event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_get_act()) == LV_DIR_LEFT ) {
|
||
lv_indev_wait_release(lv_indev_get_act());
|
||
const char *next_img = get_next_image();
|
||
if(next_img) {
|
||
update_ui_ImgBle(next_img);
|
||
}
|
||
}
|
||
if ( event_code == LV_EVENT_GESTURE && lv_indev_get_gesture_dir(lv_indev_get_act()) == LV_DIR_RIGHT ) {
|
||
lv_indev_wait_release(lv_indev_get_act());
|
||
const char *prev_img = get_prev_image();
|
||
if(prev_img) {
|
||
update_ui_ImgBle(prev_img);
|
||
}
|
||
}
|
||
}
|
||
|
||
// build funtions
|
||
|
||
void ui_ScreenImg_screen_init(void)
|
||
{
|
||
ui_ScreenImg = lv_obj_create(NULL);
|
||
lv_obj_clear_flag( ui_ScreenImg, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ImgBle = lv_img_create(ui_ScreenImg);
|
||
lv_img_set_src(ui_ImgBle, &ui_img_s1_png);
|
||
lv_obj_set_width( ui_ImgBle, 360);
|
||
lv_obj_set_height( ui_ImgBle, 360);
|
||
lv_obj_set_align( ui_ImgBle, LV_ALIGN_CENTER );
|
||
lv_obj_set_flex_flow(ui_ImgBle,LV_FLEX_FLOW_ROW);
|
||
lv_obj_set_flex_align(ui_ImgBle, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
||
lv_obj_add_flag( ui_ImgBle, LV_OBJ_FLAG_ADV_HITTEST ); /// Flags
|
||
lv_obj_clear_flag( ui_ImgBle, LV_OBJ_FLAG_SCROLLABLE ); /// Flags
|
||
|
||
ui_ContainerDle = lv_obj_create(ui_ScreenImg);
|
||
lv_obj_remove_style_all(ui_ContainerDle);
|
||
lv_obj_set_width( ui_ContainerDle, 360);
|
||
lv_obj_set_height( ui_ContainerDle, 360); // 圆形容器
|
||
lv_obj_set_x( ui_ContainerDle, 0 );
|
||
lv_obj_set_y( ui_ContainerDle, 240 ); // 向下偏移 240px(显示顶部 1/3)
|
||
lv_obj_set_align( ui_ContainerDle, LV_ALIGN_CENTER );
|
||
lv_obj_clear_flag( ui_ContainerDle, LV_OBJ_FLAG_CLICKABLE | LV_OBJ_FLAG_SCROLLABLE );
|
||
// 设置圆形和裁剪
|
||
lv_obj_set_style_radius(ui_ContainerDle, 180, LV_PART_MAIN); // 圆角半径 180
|
||
lv_obj_set_style_clip_corner(ui_ContainerDle, true, LV_PART_MAIN); // 裁剪圆角外内容
|
||
lv_obj_set_style_bg_color(ui_ContainerDle, lv_color_hex(0x000000), LV_PART_MAIN);
|
||
lv_obj_set_style_bg_opa(ui_ContainerDle, 180, LV_PART_MAIN); // 半透明(180/255 约 70%)
|
||
lv_obj_add_flag( ui_ContainerDle, LV_OBJ_FLAG_HIDDEN ); // 默认隐藏
|
||
|
||
ui_ImageDel = lv_img_create(ui_ContainerDle);
|
||
lv_img_set_src(ui_ImageDel, &ui_img_s13_png);
|
||
lv_obj_set_width( ui_ImageDel, LV_SIZE_CONTENT);
|
||
lv_obj_set_height( ui_ImageDel, LV_SIZE_CONTENT);
|
||
lv_obj_set_x( ui_ImageDel, -60 ); // 左侧位置
|
||
lv_obj_set_y( ui_ImageDel, -120 ); // 容器顶部区域(屏幕底部可见区域)
|
||
lv_obj_set_align( ui_ImageDel, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImageDel, LV_OBJ_FLAG_CLICKABLE ); // 可点击
|
||
lv_obj_clear_flag( ui_ImageDel, LV_OBJ_FLAG_SCROLLABLE );
|
||
|
||
ui_ImageReturn = lv_img_create(ui_ContainerDle);
|
||
lv_img_set_src(ui_ImageReturn, &ui_img_s14_png);
|
||
lv_obj_set_width( ui_ImageReturn, LV_SIZE_CONTENT);
|
||
lv_obj_set_height( ui_ImageReturn, LV_SIZE_CONTENT);
|
||
lv_obj_set_x( ui_ImageReturn, 60 ); // 右侧位置
|
||
lv_obj_set_y( ui_ImageReturn, -120 ); // 容器顶部区域(屏幕底部可见区域)
|
||
lv_obj_set_align( ui_ImageReturn, LV_ALIGN_CENTER );
|
||
lv_obj_add_flag( ui_ImageReturn, LV_OBJ_FLAG_CLICKABLE ); // 可点击
|
||
lv_obj_clear_flag( ui_ImageReturn, LV_OBJ_FLAG_SCROLLABLE );
|
||
|
||
// 添加点击事件回调
|
||
lv_obj_add_event_cb(ui_ImageDel, ui_event_ImageDel, LV_EVENT_ALL, NULL);
|
||
lv_obj_add_event_cb(ui_ImageReturn, ui_event_ImageReturn, LV_EVENT_ALL, NULL);
|
||
|
||
lv_obj_add_event_cb(ui_ScreenImg, ui_event_ScreenImg, LV_EVENT_ALL, NULL);
|
||
|
||
// 注意:不在此处加载图片,延迟到 LV_EVENT_SCREEN_LOADED 事件中加载
|
||
// 这样避免ui_init()时触发渲染导致开机闪烁
|
||
}
|
||
|
||
void ui_ScreenImg_screen_destroy(void)
|
||
{
|
||
if (ui_ScreenImg) lv_obj_del(ui_ScreenImg);
|
||
|
||
// NULL screen variables
|
||
ui_ScreenImg= NULL;
|
||
ui_ImgBle= NULL;
|
||
ui_ContainerDle= NULL;
|
||
ui_ImageDel= NULL;
|
||
ui_ImageReturn= NULL;
|
||
|
||
// 重置首次加载标志,下次进入时重新初始化
|
||
first_load = true;
|
||
|
||
free_spiffs_image_list();
|
||
}
|