diff --git a/CHANGELOG.md b/CHANGELOG.md index 018b7d3..208e9c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 2026-10-17 — UI layout refresh + +- Compact 320x240 layout: header status, capacity hero, usage bar, dual actions. +- Drop on-screen touch debug cursor; keep calibrated touch.cpp unchanged. + ## 2026-10-17 — Restore TF + speaker (touch map frozen) - Re-add SD info UI and speaker ON/OFF + Play Music. diff --git a/firmware/cyd/VERSION.txt b/firmware/cyd/VERSION.txt index f819a68..2b4b0c9 100644 --- a/firmware/cyd/VERSION.txt +++ b/firmware/cyd/VERSION.txt @@ -1,5 +1,5 @@ name: CYD TF card + touch speaker (cyd) -git: 7b5f984 +git: 7c6eb9a date: 2026-10-17 board: ESP32-2432S028R (ILI9341) features: TF/SD info, SoftSPI touch, GPIO26 speaker @@ -12,5 +12,5 @@ offsets: sha256: bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8 boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0 - firmware.bin D2A9F0E360CCA1ED115E042A3127D6D9C990E84B12CD972D713A46AF8A4D4A46 + firmware.bin C2BD52279AFB3E40C45358CA05493EF0255F708858A3F5132417AEAC0B6EE25F partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1 diff --git a/firmware/cyd/firmware.bin b/firmware/cyd/firmware.bin index 1d4efe0..d911242 100644 Binary files a/firmware/cyd/firmware.bin and b/firmware/cyd/firmware.bin differ diff --git a/src/main.cpp b/src/main.cpp index f45d0ff..0c7de53 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -79,7 +79,6 @@ void loop() { if (now - last_btn_ui_ms >= 200) { last_btn_ui_ms = now; ui_refresh_audio_buttons(); - ui_set_touch_debug(g_dbg_logic_x, g_dbg_logic_y, g_dbg_touch_down); } delay(5); diff --git a/src/ui.cpp b/src/ui.cpp index 42a3135..c68fe35 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -5,42 +5,37 @@ #include #include -static lv_obj_t *lbl_status; -static lv_obj_t *lbl_type; -static lv_obj_t *lbl_fs; +// 紧凑横屏仪表:顶栏状态 → 容量主信息 → 底栏操作(触控区保持大) +static constexpr uint32_t COL_BG = 0x0A1016; +static constexpr uint32_t COL_INK = 0xEAF0F6; +static constexpr uint32_t COL_MUTED = 0x7A8B9C; +static constexpr uint32_t COL_LINE = 0x1C2A38; +static constexpr uint32_t COL_OK = 0x3DDC97; +static constexpr uint32_t COL_BAD = 0xE85D4C; +static constexpr uint32_t COL_ACCENT = 0x4FC3F7; +static constexpr uint32_t COL_BTN_OFF = 0x243140; +static constexpr uint32_t COL_BTN_ON = 0x1B5E4A; +static constexpr uint32_t COL_BTN_PLAY = 0x1A4A6E; +static constexpr uint32_t COL_BTN_STOP = 0x8B2E2E; + +static lv_obj_t *lbl_title; +static lv_obj_t *lbl_chip; static lv_obj_t *lbl_capacity; +static lv_obj_t *lbl_meta; static lv_obj_t *lbl_audio; static lv_obj_t *bar_usage; static lv_obj_t *btn_speaker; static lv_obj_t *btn_play; static lv_obj_t *lbl_speaker; static lv_obj_t *lbl_play; -static lv_obj_t *lbl_touch_dbg; -static lv_obj_t *touch_cursor; -static lv_obj_t *make_row(lv_obj_t *parent, const char *title, lv_obj_t **value_out) { - lv_obj_t *row = lv_obj_create(parent); - lv_obj_set_width(row, LV_PCT(100)); - lv_obj_set_height(row, LV_SIZE_CONTENT); - lv_obj_set_style_bg_opa(row, LV_OPA_TRANSP, 0); - lv_obj_set_style_border_width(row, 0, 0); - lv_obj_set_style_pad_all(row, 1, 0); - lv_obj_set_flex_flow(row, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(row, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_CENTER); - lv_obj_clear_flag(row, LV_OBJ_FLAG_SCROLLABLE); - - lv_obj_t *t = lv_label_create(row); - lv_label_set_text(t, title); - lv_obj_set_style_text_color(t, lv_color_hex(0x90A4AE), 0); - lv_obj_set_style_text_font(t, &lv_font_montserrat_14, 0); - - lv_obj_t *v = lv_label_create(row); - lv_label_set_text(v, "—"); - lv_obj_set_style_text_color(v, lv_color_hex(0xECEFF1), 0); - lv_obj_set_style_text_font(v, &lv_font_montserrat_14, 0); - *value_out = v; - return row; +static void style_btn(lv_obj_t *btn, uint32_t bg) { + lv_obj_set_style_radius(btn, 10, 0); + lv_obj_set_style_bg_color(btn, lv_color_hex(bg), 0); + lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0); + lv_obj_set_style_shadow_width(btn, 0, 0); + lv_obj_set_style_border_width(btn, 0, 0); + lv_obj_set_style_pad_all(btn, 0, 0); } static void on_speaker_clicked(lv_event_t *e) { @@ -61,25 +56,20 @@ static void on_play_clicked(lv_event_t *e) { void ui_refresh_audio_buttons() { if (lbl_speaker) { - char buf[28]; - snprintf(buf, sizeof(buf), "%s %u%%", - audio_is_enabled() ? "Speaker ON" : "Speaker OFF", - (unsigned)audio_get_volume()); + char buf[24]; + snprintf(buf, sizeof(buf), "%s %u%%", + audio_is_enabled() ? "ON" : "OFF", (unsigned)audio_get_volume()); lv_label_set_text(lbl_speaker, buf); } if (btn_speaker) { - lv_obj_set_style_bg_color( - btn_speaker, - audio_is_enabled() ? lv_color_hex(0x2E7D32) : lv_color_hex(0x455A64), 0); + style_btn(btn_speaker, audio_is_enabled() ? COL_BTN_ON : COL_BTN_OFF); } if (lbl_play) { - lv_label_set_text(lbl_play, audio_is_playing() ? "Stop" : "Play Music"); + lv_label_set_text(lbl_play, audio_is_playing() ? "STOP" : "PLAY"); } if (btn_play) { - lv_obj_set_style_bg_color( - btn_play, - audio_is_playing() ? lv_color_hex(0xC62828) : lv_color_hex(0x1565C0), 0); + style_btn(btn_play, audio_is_playing() ? COL_BTN_STOP : COL_BTN_PLAY); } if (lbl_audio) { @@ -89,129 +79,140 @@ void ui_refresh_audio_buttons() { void ui_create() { lv_obj_t *scr = lv_screen_active(); - lv_obj_set_style_bg_color(scr, lv_color_hex(0x0D1B2A), 0); + lv_obj_set_style_bg_color(scr, lv_color_hex(COL_BG), 0); lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0); + lv_obj_clear_flag(scr, LV_OBJ_FLAG_SCROLLABLE); - lv_obj_t *col = lv_obj_create(scr); - lv_obj_set_size(col, LV_PCT(100), LV_PCT(100)); - lv_obj_set_style_bg_opa(col, LV_OPA_TRANSP, 0); - lv_obj_set_style_border_width(col, 0, 0); - lv_obj_set_style_pad_left(col, 10, 0); - lv_obj_set_style_pad_right(col, 10, 0); - lv_obj_set_style_pad_top(col, 6, 0); - lv_obj_set_style_pad_bottom(col, 6, 0); - lv_obj_set_flex_flow(col, LV_FLEX_FLOW_COLUMN); - lv_obj_set_flex_align(col, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_CENTER); - lv_obj_set_style_pad_row(col, 2, 0); - lv_obj_clear_flag(col, LV_OBJ_FLAG_SCROLLABLE); + // —— 顶栏 —— + lbl_title = lv_label_create(scr); + lv_label_set_text(lbl_title, "CYD"); + lv_obj_set_style_text_font(lbl_title, &lv_font_montserrat_20, 0); + lv_obj_set_style_text_color(lbl_title, lv_color_hex(COL_ACCENT), 0); + lv_obj_set_pos(lbl_title, 14, 10); - lv_obj_t *title = lv_label_create(col); - lv_label_set_text(title, "TF + Speaker"); - lv_obj_set_style_text_font(title, &lv_font_montserrat_18, 0); - lv_obj_set_style_text_color(title, lv_color_hex(0x4FC3F7), 0); + lbl_chip = lv_label_create(scr); + lv_label_set_text(lbl_chip, "—"); + lv_obj_set_style_text_font(lbl_chip, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(lbl_chip, lv_color_hex(COL_MUTED), 0); + lv_obj_align(lbl_chip, LV_ALIGN_TOP_RIGHT, -14, 14); - make_row(col, "Status", &lbl_status); - make_row(col, "Type", &lbl_type); - make_row(col, "Format", &lbl_fs); - make_row(col, "Capacity", &lbl_capacity); - make_row(col, "Audio", &lbl_audio); + lv_obj_t *rule = lv_obj_create(scr); + lv_obj_set_size(rule, UI_HOR_RES - 28, 1); + lv_obj_set_pos(rule, 14, 40); + lv_obj_set_style_bg_color(rule, lv_color_hex(COL_LINE), 0); + lv_obj_set_style_bg_opa(rule, LV_OPA_COVER, 0); + lv_obj_set_style_border_width(rule, 0, 0); + lv_obj_set_style_radius(rule, 0, 0); + lv_obj_clear_flag(rule, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_clear_flag(rule, LV_OBJ_FLAG_CLICKABLE); - bar_usage = lv_bar_create(col); - lv_obj_set_width(bar_usage, LV_PCT(100)); - lv_obj_set_height(bar_usage, 10); + // —— 主信息:容量 —— + lv_obj_t *cap_hint = lv_label_create(scr); + lv_label_set_text(cap_hint, "CAPACITY"); + lv_obj_set_style_text_font(cap_hint, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(cap_hint, lv_color_hex(COL_MUTED), 0); + lv_obj_set_pos(cap_hint, 14, 52); + + lbl_capacity = lv_label_create(scr); + lv_label_set_text(lbl_capacity, "—"); + lv_obj_set_style_text_font(lbl_capacity, &lv_font_montserrat_20, 0); + lv_obj_set_style_text_color(lbl_capacity, lv_color_hex(COL_INK), 0); + lv_obj_set_pos(lbl_capacity, 14, 72); + + lbl_meta = lv_label_create(scr); + lv_label_set_text(lbl_meta, "Type — · FS —"); + lv_obj_set_style_text_font(lbl_meta, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(lbl_meta, lv_color_hex(COL_MUTED), 0); + lv_obj_set_pos(lbl_meta, 14, 100); + + bar_usage = lv_bar_create(scr); + lv_obj_set_size(bar_usage, UI_HOR_RES - 28, 8); + lv_obj_set_pos(bar_usage, 14, 124); lv_bar_set_range(bar_usage, 0, 100); lv_bar_set_value(bar_usage, 0, LV_ANIM_OFF); - lv_obj_set_style_bg_color(bar_usage, lv_color_hex(0x263238), 0); - lv_obj_set_style_bg_color(bar_usage, lv_color_hex(0x29B6F6), LV_PART_INDICATOR); + lv_obj_set_style_radius(bar_usage, 4, 0); + lv_obj_set_style_bg_color(bar_usage, lv_color_hex(COL_LINE), 0); + lv_obj_set_style_bg_color(bar_usage, lv_color_hex(COL_ACCENT), LV_PART_INDICATOR); + lv_obj_set_style_radius(bar_usage, 4, LV_PART_INDICATOR); - lv_obj_t *row_btns = lv_obj_create(col); - lv_obj_set_width(row_btns, LV_PCT(100)); - lv_obj_set_height(row_btns, 64); - lv_obj_set_style_bg_opa(row_btns, LV_OPA_TRANSP, 0); - lv_obj_set_style_border_width(row_btns, 0, 0); - lv_obj_set_style_pad_all(row_btns, 0, 0); - lv_obj_set_flex_flow(row_btns, LV_FLEX_FLOW_ROW); - lv_obj_set_flex_align(row_btns, LV_FLEX_ALIGN_SPACE_BETWEEN, LV_FLEX_ALIGN_CENTER, - LV_FLEX_ALIGN_CENTER); - lv_obj_clear_flag(row_btns, LV_OBJ_FLAG_SCROLLABLE); + lbl_audio = lv_label_create(scr); + lv_label_set_text(lbl_audio, "Speaker OFF"); + lv_obj_set_style_text_font(lbl_audio, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(lbl_audio, lv_color_hex(COL_MUTED), 0); + lv_obj_set_pos(lbl_audio, 14, 140); - btn_speaker = lv_button_create(row_btns); - lv_obj_set_size(btn_speaker, 150, 60); - lv_obj_set_style_radius(btn_speaker, 8, 0); + // —— 底栏双按钮(大命中区)—— + const int btn_y = 168; + const int btn_h = 58; + const int gap = 10; + const int btn_w = (UI_HOR_RES - 28 - gap) / 2; + + btn_speaker = lv_button_create(scr); + lv_obj_set_pos(btn_speaker, 14, btn_y); + lv_obj_set_size(btn_speaker, btn_w, btn_h); lv_obj_add_flag(btn_speaker, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(btn_speaker, on_speaker_clicked, LV_EVENT_CLICKED, nullptr); - lbl_speaker = lv_label_create(btn_speaker); - lv_label_set_text(lbl_speaker, "Speaker OFF"); - lv_obj_set_style_text_font(lbl_speaker, &lv_font_montserrat_14, 0); - lv_obj_center(lbl_speaker); + style_btn(btn_speaker, COL_BTN_OFF); - btn_play = lv_button_create(row_btns); - lv_obj_set_size(btn_play, 150, 60); - lv_obj_set_style_radius(btn_play, 8, 0); + lv_obj_t *spk_cap = lv_label_create(btn_speaker); + lv_label_set_text(spk_cap, "SPEAKER"); + lv_obj_set_style_text_font(spk_cap, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(spk_cap, lv_color_hex(COL_MUTED), 0); + lv_obj_align(spk_cap, LV_ALIGN_TOP_MID, 0, 8); + + lbl_speaker = lv_label_create(btn_speaker); + lv_label_set_text(lbl_speaker, "OFF 20%"); + lv_obj_set_style_text_font(lbl_speaker, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_color(lbl_speaker, lv_color_hex(COL_INK), 0); + lv_obj_align(lbl_speaker, LV_ALIGN_BOTTOM_MID, 0, -10); + + btn_play = lv_button_create(scr); + lv_obj_set_pos(btn_play, 14 + btn_w + gap, btn_y); + lv_obj_set_size(btn_play, btn_w, btn_h); lv_obj_add_flag(btn_play, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(btn_play, on_play_clicked, LV_EVENT_CLICKED, nullptr); + style_btn(btn_play, COL_BTN_PLAY); + + lv_obj_t *play_cap = lv_label_create(btn_play); + lv_label_set_text(play_cap, "MUSIC"); + lv_obj_set_style_text_font(play_cap, &lv_font_montserrat_14, 0); + lv_obj_set_style_text_color(play_cap, lv_color_hex(COL_MUTED), 0); + lv_obj_align(play_cap, LV_ALIGN_TOP_MID, 0, 8); + lbl_play = lv_label_create(btn_play); - lv_label_set_text(lbl_play, "Play Music"); - lv_obj_set_style_text_font(lbl_play, &lv_font_montserrat_14, 0); - lv_obj_center(lbl_play); - - lbl_touch_dbg = lv_label_create(col); - lv_label_set_text(lbl_touch_dbg, "Touch: --"); - lv_obj_set_style_text_font(lbl_touch_dbg, &lv_font_montserrat_14, 0); - lv_obj_set_style_text_color(lbl_touch_dbg, lv_color_hex(0xFFB74D), 0); - - touch_cursor = lv_obj_create(scr); - lv_obj_set_size(touch_cursor, 14, 14); - lv_obj_set_style_radius(touch_cursor, LV_RADIUS_CIRCLE, 0); - lv_obj_set_style_bg_color(touch_cursor, lv_color_hex(0xFF5252), 0); - lv_obj_set_style_bg_opa(touch_cursor, LV_OPA_COVER, 0); - lv_obj_set_style_border_width(touch_cursor, 1, 0); - lv_obj_set_style_border_color(touch_cursor, lv_color_hex(0xFFFFFF), 0); - lv_obj_add_flag(touch_cursor, LV_OBJ_FLAG_HIDDEN); - lv_obj_clear_flag(touch_cursor, LV_OBJ_FLAG_CLICKABLE); - lv_obj_clear_flag(touch_cursor, LV_OBJ_FLAG_SCROLLABLE); + lv_label_set_text(lbl_play, "PLAY"); + lv_obj_set_style_text_font(lbl_play, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_color(lbl_play, lv_color_hex(COL_INK), 0); + lv_obj_align(lbl_play, LV_ALIGN_BOTTOM_MID, 0, -10); ui_refresh_audio_buttons(); } -void ui_set_touch_debug(int16_t lx, int16_t ly, bool down) { - if (!lbl_touch_dbg) { - return; - } - if (!down) { - lv_label_set_text(lbl_touch_dbg, "Touch: up"); - if (touch_cursor) { - lv_obj_add_flag(touch_cursor, LV_OBJ_FLAG_HIDDEN); - } - return; - } - char buf[40]; - snprintf(buf, sizeof(buf), "Touch %d,%d", (int)lx, (int)ly); - lv_label_set_text(lbl_touch_dbg, buf); - if (touch_cursor) { - lv_obj_clear_flag(touch_cursor, LV_OBJ_FLAG_HIDDEN); - lv_obj_set_pos(touch_cursor, lx - 7, ly - 7); - lv_obj_move_foreground(touch_cursor); - } +void ui_set_touch_debug(int16_t /*lx*/, int16_t /*ly*/, bool /*down*/) { + // 触控已标定;界面不再显示调试光标 } void ui_update(const SdCardInfo &info) { if (!info.mounted || !info.present) { - lv_label_set_text(lbl_status, info.error.length() ? info.error.c_str() : "Fail"); - lv_obj_set_style_text_color(lbl_status, lv_color_hex(0xEF5350), 0); - lv_label_set_text(lbl_type, info.type); - lv_label_set_text(lbl_fs, "—"); + lv_label_set_text(lbl_chip, info.error.length() ? info.error.c_str() : "FAIL"); + lv_obj_set_style_text_color(lbl_chip, lv_color_hex(COL_BAD), 0); lv_label_set_text(lbl_capacity, "—"); + lv_label_set_text(lbl_meta, "No card"); lv_bar_set_value(bar_usage, 0, LV_ANIM_OFF); } else { - lv_label_set_text(lbl_status, "Mounted OK"); - lv_obj_set_style_text_color(lbl_status, lv_color_hex(0x66BB6A), 0); - lv_label_set_text(lbl_type, info.type); - lv_label_set_text(lbl_fs, info.filesystem); + char chip[32]; + snprintf(chip, sizeof(chip), "OK · %s", info.type); + lv_label_set_text(lbl_chip, chip); + lv_obj_set_style_text_color(lbl_chip, lv_color_hex(COL_OK), 0); + String cap = format_bytes(info.card_bytes); lv_label_set_text(lbl_capacity, cap.c_str()); + char meta[48]; + snprintf(meta, sizeof(meta), "%s · %s · %u files", info.type, + info.filesystem, (unsigned)info.root_files); + lv_label_set_text(lbl_meta, meta); + int pct = 0; if (info.total_bytes > 0) { pct = static_cast((info.used_bytes * 100ULL) / info.total_bytes);