fix 3.5 reboot after WiFi scan list OOM.
Cap list to top 8 by RSSI, lazy status/password UI, single-button rows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
name: CYD wifitest (cyd_35r)
|
||||
git: 9cbbb29
|
||||
git: d9773a8
|
||||
date: 2026-10-25
|
||||
board: ESP32-3248S035 (ST7796)
|
||||
flash_size: 4MB
|
||||
@@ -11,5 +11,5 @@ offsets:
|
||||
sha256:
|
||||
bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8
|
||||
boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0
|
||||
firmware.bin DDB6B8EB5091F9C201A1696CEC05BA68E93A512EE7388C66EC7207850B74FC85
|
||||
firmware.bin 07AE55AB62FE6A53D343B0DDB1E2FE422581F6B02CD1E62E3161AE66C3056897
|
||||
partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1
|
||||
|
||||
Binary file not shown.
326
src/wifi_ui.cpp
326
src/wifi_ui.cpp
@@ -18,6 +18,9 @@ static constexpr uint32_t COL_BTN = 0x243140;
|
||||
static constexpr uint32_t COL_BTN_ACC = 0x1A4A6E;
|
||||
static constexpr uint32_t COL_BTN_WARN = 0x6B3A1E;
|
||||
|
||||
/* 3.5" LV_MEM=32K: dual screens + 16 heavy rows OOMs. Cap list hard. */
|
||||
static constexpr int WIFI_UI_LIST_MAX = 8;
|
||||
|
||||
static lv_obj_t *scr_status = nullptr;
|
||||
static lv_obj_t *scr_setup = nullptr;
|
||||
static lv_obj_t *lbl_title = nullptr;
|
||||
@@ -42,9 +45,24 @@ static char g_pick_ssid[WIFI_PROV_SSID_MAX + 1] = {};
|
||||
static bool g_on_setup = false;
|
||||
static bool g_pass_visible = false;
|
||||
static bool g_scan_pending = false;
|
||||
static bool g_auto_scan_armed = false;
|
||||
static uint32_t g_auto_scan_at = 0;
|
||||
static WifiProvState g_last_shown = WIFI_PROV_IDLE;
|
||||
static uint32_t g_last_status_ms = 0;
|
||||
|
||||
static void on_scan(lv_event_t *e);
|
||||
static void on_portal(lv_event_t *e);
|
||||
static void on_join(lv_event_t *e);
|
||||
static void on_dlg_back(lv_event_t *e);
|
||||
static void on_toggle_pass(lv_event_t *e);
|
||||
static void on_kb(lv_event_t *e);
|
||||
static void on_change_wifi(lv_event_t *e);
|
||||
static void on_forget(lv_event_t *e);
|
||||
static void on_row_join(lv_event_t *e);
|
||||
static void build_status();
|
||||
static void build_setup();
|
||||
static void ensure_pass_dialog();
|
||||
|
||||
static void style_btn(lv_obj_t *btn, uint32_t bg) {
|
||||
lv_obj_set_style_radius(btn, 8, 0);
|
||||
lv_obj_set_style_bg_color(btn, lv_color_hex(bg), 0);
|
||||
@@ -59,15 +77,19 @@ static void style_btn(lv_obj_t *btn, uint32_t bg) {
|
||||
static lv_obj_t *make_btn(lv_obj_t *parent, const char *text, uint32_t bg,
|
||||
lv_event_cb_t cb, int w, int h) {
|
||||
lv_obj_t *btn = lv_button_create(parent);
|
||||
if (!btn) {
|
||||
return nullptr;
|
||||
}
|
||||
lv_obj_set_size(btn, w, h);
|
||||
style_btn(btn, bg);
|
||||
lv_obj_t *lab = lv_label_create(btn);
|
||||
lv_label_set_text(lab, text);
|
||||
lv_obj_set_style_text_color(lab, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(lab, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(lab);
|
||||
/* Label must not steal clicks from the button. */
|
||||
lv_obj_clear_flag(lab, LV_OBJ_FLAG_CLICKABLE);
|
||||
if (lab) {
|
||||
lv_label_set_text(lab, text);
|
||||
lv_obj_set_style_text_color(lab, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(lab, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(lab);
|
||||
lv_obj_clear_flag(lab, LV_OBJ_FLAG_CLICKABLE);
|
||||
}
|
||||
if (cb) {
|
||||
lv_obj_add_event_cb(btn, cb, LV_EVENT_CLICKED, nullptr);
|
||||
}
|
||||
@@ -93,8 +115,6 @@ static void set_pass_visible(bool visible) {
|
||||
}
|
||||
}
|
||||
|
||||
static void on_kb(lv_event_t *e); /* defined below — used by ensure_keyboard */
|
||||
|
||||
static void ensure_keyboard() {
|
||||
if (kb || !scr_setup || !ta_pass) {
|
||||
return;
|
||||
@@ -112,7 +132,101 @@ static void ensure_keyboard() {
|
||||
lv_obj_add_flag(kb, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void ensure_pass_dialog() {
|
||||
if (overlay || !scr_setup) {
|
||||
return;
|
||||
}
|
||||
|
||||
overlay = lv_obj_create(scr_setup);
|
||||
if (!overlay) {
|
||||
Serial.println("[ui] OOM: pass overlay");
|
||||
return;
|
||||
}
|
||||
lv_obj_set_size(overlay, UI_HOR_RES, UI_VER_RES);
|
||||
lv_obj_set_style_bg_color(overlay, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_bg_opa(overlay, LV_OPA_70, 0);
|
||||
lv_obj_set_style_border_width(overlay, 0, 0);
|
||||
lv_obj_set_style_pad_all(overlay, 0, 0);
|
||||
lv_obj_clear_flag(overlay, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(overlay, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
dlg = lv_obj_create(overlay);
|
||||
if (!dlg) {
|
||||
return;
|
||||
}
|
||||
lv_obj_set_size(dlg, UI_HOR_RES - UW(20), UH(100));
|
||||
lv_obj_align(dlg, LV_ALIGN_TOP_MID, UX(0), UY(8));
|
||||
lv_obj_set_style_bg_color(dlg, lv_color_hex(0x15202C), 0);
|
||||
lv_obj_set_style_border_width(dlg, 0, 0);
|
||||
lv_obj_set_style_radius(dlg, 10, 0);
|
||||
lv_obj_set_style_pad_all(dlg, 8, 0);
|
||||
lv_obj_clear_flag(dlg, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lbl_dlg_ssid = lv_label_create(dlg);
|
||||
if (lbl_dlg_ssid) {
|
||||
lv_label_set_text(lbl_dlg_ssid, "");
|
||||
lv_obj_set_style_text_color(lbl_dlg_ssid, lv_color_hex(COL_ACCENT), 0);
|
||||
lv_obj_set_style_text_font(lbl_dlg_ssid, &lv_font_montserrat_14, 0);
|
||||
lv_obj_align(lbl_dlg_ssid, LV_ALIGN_TOP_LEFT, UX(0), UY(0));
|
||||
}
|
||||
|
||||
lv_obj_t *pass_row = lv_obj_create(dlg);
|
||||
if (pass_row) {
|
||||
lv_obj_set_size(pass_row, UI_HOR_RES - UW(40), UH(32));
|
||||
lv_obj_align(pass_row, LV_ALIGN_TOP_LEFT, UX(0), UY(22));
|
||||
lv_obj_set_style_bg_opa(pass_row, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(pass_row, 0, 0);
|
||||
lv_obj_set_style_pad_all(pass_row, 0, 0);
|
||||
lv_obj_set_flex_flow(pass_row, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(pass_row, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(pass_row, UW(6), 0);
|
||||
lv_obj_clear_flag(pass_row, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
ta_pass = lv_textarea_create(pass_row);
|
||||
if (ta_pass) {
|
||||
lv_obj_set_size(ta_pass, UI_HOR_RES - UW(40) - UW(62), UH(32));
|
||||
lv_textarea_set_one_line(ta_pass, true);
|
||||
lv_textarea_set_password_mode(ta_pass, true);
|
||||
lv_textarea_set_placeholder_text(ta_pass, "Password");
|
||||
lv_obj_set_style_text_font(ta_pass, &lv_font_montserrat_14, 0);
|
||||
}
|
||||
|
||||
btn_show_pass = lv_button_create(pass_row);
|
||||
if (btn_show_pass) {
|
||||
lv_obj_set_size(btn_show_pass, UW(56), UH(28));
|
||||
style_btn(btn_show_pass, COL_BTN);
|
||||
lbl_show_pass = lv_label_create(btn_show_pass);
|
||||
if (lbl_show_pass) {
|
||||
lv_label_set_text(lbl_show_pass, "Show");
|
||||
lv_obj_set_style_text_color(lbl_show_pass, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(lbl_show_pass, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(lbl_show_pass);
|
||||
lv_obj_clear_flag(lbl_show_pass, LV_OBJ_FLAG_CLICKABLE);
|
||||
}
|
||||
lv_obj_add_event_cb(btn_show_pass, on_toggle_pass, LV_EVENT_CLICKED,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
lv_obj_t *row = lv_obj_create(dlg);
|
||||
if (row) {
|
||||
lv_obj_set_size(row, UI_HOR_RES - UW(40), UH(28));
|
||||
lv_obj_align(row, LV_ALIGN_BOTTOM_MID, UX(0), UY(0));
|
||||
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, 0, 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);
|
||||
make_btn(row, "Back", COL_BTN, on_dlg_back, UW(70), UH(26));
|
||||
make_btn(row, "Join", COL_BTN_ACC, on_join, UW(70), UH(26));
|
||||
}
|
||||
}
|
||||
|
||||
static void show_password_dialog(const char *ssid) {
|
||||
ensure_pass_dialog();
|
||||
strncpy(g_pick_ssid, ssid, WIFI_PROV_SSID_MAX);
|
||||
g_pick_ssid[WIFI_PROV_SSID_MAX] = '\0';
|
||||
if (lbl_dlg_ssid) {
|
||||
@@ -152,6 +266,18 @@ static void on_row_join(lv_event_t *e) {
|
||||
show_password_dialog(g_items[idx].ssid);
|
||||
}
|
||||
|
||||
static void sort_items_by_rssi() {
|
||||
for (int i = 0; i + 1 < g_item_n; ++i) {
|
||||
for (int j = i + 1; j < g_item_n; ++j) {
|
||||
if (g_items[j].rssi > g_items[i].rssi) {
|
||||
WifiScanItem tmp = g_items[i];
|
||||
g_items[i] = g_items[j];
|
||||
g_items[j] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rebuild_list() {
|
||||
if (!list_wifi) {
|
||||
return;
|
||||
@@ -160,67 +286,57 @@ static void rebuild_list() {
|
||||
|
||||
if (g_item_n <= 0) {
|
||||
lv_obj_t *lab = lv_label_create(list_wifi);
|
||||
if (!lab) {
|
||||
return;
|
||||
if (lab) {
|
||||
lv_label_set_text(lab, "No networks. Tap Scan.");
|
||||
lv_obj_set_style_text_color(lab, lv_color_hex(COL_MUTED), 0);
|
||||
}
|
||||
lv_label_set_text(lab, "No networks. Tap Scan.");
|
||||
lv_obj_set_style_text_color(lab, lv_color_hex(COL_MUTED), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Compact rows (label + Join) — 3.5 UI + keyboard needs LV_MEM headroom. */
|
||||
for (int i = 0; i < g_item_n; ++i) {
|
||||
lv_obj_t *row = lv_obj_create(list_wifi);
|
||||
if (!row) {
|
||||
Serial.printf("[ui] OOM at wifi row %d/%d\n", i, g_item_n);
|
||||
sort_items_by_rssi();
|
||||
const int n =
|
||||
g_item_n > WIFI_UI_LIST_MAX ? WIFI_UI_LIST_MAX : g_item_n;
|
||||
|
||||
/* One button per SSID — avoid nested row/label/button (OOM on 3.5). */
|
||||
for (int i = 0; i < n; ++i) {
|
||||
char line[56];
|
||||
snprintf(line, sizeof(line), "%s %ddBm", g_items[i].ssid,
|
||||
(int)g_items[i].rssi);
|
||||
|
||||
lv_obj_t *btn = lv_button_create(list_wifi);
|
||||
if (!btn) {
|
||||
Serial.printf("[ui] OOM at wifi row %d/%d\n", i, n);
|
||||
break;
|
||||
}
|
||||
lv_obj_set_width(row, lv_pct(100));
|
||||
lv_obj_set_height(row, UH(34));
|
||||
lv_obj_set_style_bg_color(row, lv_color_hex(0x121A24), 0);
|
||||
lv_obj_set_style_bg_opa(row, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(row, 0, 0);
|
||||
lv_obj_set_style_radius(row, 6, 0);
|
||||
lv_obj_set_style_pad_hor(row, 6, 0);
|
||||
lv_obj_set_style_pad_ver(row, 2, 0);
|
||||
lv_obj_set_style_margin_bottom(row, 4, 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_clear_flag(row, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_add_flag(row, LV_OBJ_FLAG_EVENT_BUBBLE);
|
||||
lv_obj_set_width(btn, lv_pct(100));
|
||||
lv_obj_set_height(btn, UH(40));
|
||||
lv_obj_set_style_bg_color(btn, lv_color_hex(0x1A4A6E), 0);
|
||||
lv_obj_set_style_bg_opa(btn, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_radius(btn, 6, 0);
|
||||
lv_obj_set_style_border_width(btn, 0, 0);
|
||||
lv_obj_set_style_shadow_width(btn, 0, 0);
|
||||
lv_obj_set_style_margin_bottom(btn, 4, 0);
|
||||
lv_obj_set_ext_click_area(btn, 8);
|
||||
|
||||
char line[64];
|
||||
snprintf(line, sizeof(line), LV_SYMBOL_WIFI " %s %ddBm", g_items[i].ssid,
|
||||
(int)g_items[i].rssi);
|
||||
lv_obj_t *lab = lv_label_create(row);
|
||||
lv_obj_t *lab = lv_label_create(btn);
|
||||
if (!lab) {
|
||||
break;
|
||||
}
|
||||
lv_label_set_text(lab, line);
|
||||
lv_label_set_long_mode(lab, LV_LABEL_LONG_DOT);
|
||||
lv_obj_set_flex_grow(lab, 1);
|
||||
lv_obj_set_width(lab, lv_pct(92));
|
||||
lv_obj_set_style_text_color(lab, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(lab, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(lab);
|
||||
lv_obj_clear_flag(lab, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
lv_obj_t *join = lv_button_create(row);
|
||||
if (!join) {
|
||||
break;
|
||||
}
|
||||
lv_obj_set_size(join, UW(56), UH(28));
|
||||
style_btn(join, COL_BTN_ACC);
|
||||
lv_obj_t *jl = lv_label_create(join);
|
||||
if (jl) {
|
||||
lv_label_set_text(jl, "Join");
|
||||
lv_obj_set_style_text_color(jl, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(jl, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(jl);
|
||||
lv_obj_clear_flag(jl, LV_OBJ_FLAG_CLICKABLE);
|
||||
}
|
||||
lv_obj_add_event_cb(join, on_row_join, LV_EVENT_CLICKED,
|
||||
lv_obj_add_event_cb(btn, on_row_join, LV_EVENT_CLICKED,
|
||||
(void *)(intptr_t)i);
|
||||
}
|
||||
|
||||
if (g_item_n > WIFI_UI_LIST_MAX) {
|
||||
Serial.printf("[ui] showing top %d of %d by RSSI\n", n, g_item_n);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_scan() {
|
||||
@@ -330,6 +446,9 @@ static void refresh_status_labels() {
|
||||
}
|
||||
|
||||
static void build_status() {
|
||||
if (scr_status) {
|
||||
return;
|
||||
}
|
||||
scr_status = lv_obj_create(NULL);
|
||||
lv_obj_set_style_bg_color(scr_status, lv_color_hex(COL_BG), 0);
|
||||
lv_obj_set_style_bg_opa(scr_status, LV_OPA_COVER, 0);
|
||||
@@ -376,6 +495,9 @@ static void build_status() {
|
||||
}
|
||||
|
||||
static void build_setup() {
|
||||
if (scr_setup) {
|
||||
return;
|
||||
}
|
||||
scr_setup = lv_obj_create(NULL);
|
||||
lv_obj_set_style_bg_color(scr_setup, lv_color_hex(COL_BG), 0);
|
||||
lv_obj_set_style_bg_opa(scr_setup, LV_OPA_COVER, 0);
|
||||
@@ -404,7 +526,6 @@ static void build_setup() {
|
||||
LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(bar, UW(8), 0);
|
||||
lv_obj_clear_flag(bar, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(bar, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
make_btn(bar, "Scan", COL_BTN_ACC, on_scan, UW(90), UH(42));
|
||||
make_btn(bar, "Phone AP", COL_BTN, on_portal, UW(110), UH(42));
|
||||
@@ -424,101 +545,40 @@ static void build_setup() {
|
||||
lv_obj_set_flex_align(list_wifi, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START,
|
||||
LV_FLEX_ALIGN_START);
|
||||
lv_obj_set_scroll_dir(list_wifi, LV_DIR_VER);
|
||||
// 必须 CLICKABLE,否则列表区域收不到拖动手势,只有点到子按钮才可能滚
|
||||
lv_obj_add_flag(list_wifi, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(list_wifi, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_add_flag(list_wifi, LV_OBJ_FLAG_SCROLL_ELASTIC);
|
||||
lv_obj_add_flag(list_wifi, LV_OBJ_FLAG_SCROLL_MOMENTUM);
|
||||
|
||||
// 密码层
|
||||
overlay = lv_obj_create(scr_setup);
|
||||
lv_obj_set_size(overlay, UI_HOR_RES, UI_VER_RES);
|
||||
lv_obj_set_style_bg_color(overlay, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_bg_opa(overlay, LV_OPA_70, 0);
|
||||
lv_obj_set_style_border_width(overlay, 0, 0);
|
||||
lv_obj_set_style_pad_all(overlay, 0, 0);
|
||||
lv_obj_clear_flag(overlay, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(overlay, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
dlg = lv_obj_create(overlay);
|
||||
lv_obj_set_size(dlg, UI_HOR_RES - UW(20), UH(100));
|
||||
lv_obj_align(dlg, LV_ALIGN_TOP_MID, UX(0), UY(8));
|
||||
lv_obj_set_style_bg_color(dlg, lv_color_hex(0x15202C), 0);
|
||||
lv_obj_set_style_border_width(dlg, 0, 0);
|
||||
lv_obj_set_style_radius(dlg, 10, 0);
|
||||
lv_obj_set_style_pad_all(dlg, 8, 0);
|
||||
lv_obj_clear_flag(dlg, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
lbl_dlg_ssid = lv_label_create(dlg);
|
||||
lv_label_set_text(lbl_dlg_ssid, "");
|
||||
lv_obj_set_style_text_color(lbl_dlg_ssid, lv_color_hex(COL_ACCENT), 0);
|
||||
lv_obj_set_style_text_font(lbl_dlg_ssid, &lv_font_montserrat_14, 0);
|
||||
lv_obj_align(lbl_dlg_ssid, LV_ALIGN_TOP_LEFT, UX(0), UY(0));
|
||||
|
||||
lv_obj_t *pass_row = lv_obj_create(dlg);
|
||||
lv_obj_set_size(pass_row, UI_HOR_RES - UW(40), UH(32));
|
||||
lv_obj_align(pass_row, LV_ALIGN_TOP_LEFT, UX(0), UY(22));
|
||||
lv_obj_set_style_bg_opa(pass_row, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(pass_row, 0, 0);
|
||||
lv_obj_set_style_pad_all(pass_row, 0, 0);
|
||||
lv_obj_set_flex_flow(pass_row, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(pass_row, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER,
|
||||
LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_set_style_pad_column(pass_row, UW(6), 0);
|
||||
lv_obj_clear_flag(pass_row, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
ta_pass = lv_textarea_create(pass_row);
|
||||
lv_obj_set_size(ta_pass, UI_HOR_RES - UW(40) - UW(62), UH(32));
|
||||
lv_textarea_set_one_line(ta_pass, true);
|
||||
lv_textarea_set_password_mode(ta_pass, true);
|
||||
lv_textarea_set_placeholder_text(ta_pass, "Password");
|
||||
lv_obj_set_style_text_font(ta_pass, &lv_font_montserrat_14, 0);
|
||||
|
||||
btn_show_pass = lv_button_create(pass_row);
|
||||
lv_obj_set_size(btn_show_pass, UW(56), UH(28));
|
||||
style_btn(btn_show_pass, COL_BTN);
|
||||
lbl_show_pass = lv_label_create(btn_show_pass);
|
||||
lv_label_set_text(lbl_show_pass, "Show");
|
||||
lv_obj_set_style_text_color(lbl_show_pass, lv_color_hex(COL_INK), 0);
|
||||
lv_obj_set_style_text_font(lbl_show_pass, &lv_font_montserrat_14, 0);
|
||||
lv_obj_center(lbl_show_pass);
|
||||
lv_obj_add_event_cb(btn_show_pass, on_toggle_pass, LV_EVENT_CLICKED, nullptr);
|
||||
|
||||
lv_obj_t *row = lv_obj_create(dlg);
|
||||
lv_obj_set_size(row, UI_HOR_RES - UW(40), UH(28));
|
||||
lv_obj_align(row, LV_ALIGN_BOTTOM_MID, UX(0), UY(0));
|
||||
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, 0, 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);
|
||||
make_btn(row, "Back", COL_BTN, on_dlg_back, UW(70), UH(26));
|
||||
make_btn(row, "Join", COL_BTN_ACC, on_join, UW(70), UH(26));
|
||||
/* Keyboard is created lazily in show_password_dialog (saves LV_MEM on 3.5). */
|
||||
/* Password dialog + keyboard created lazily — keep LV_MEM free for scan list. */
|
||||
}
|
||||
|
||||
void wifi_ui_create() {
|
||||
build_status();
|
||||
build_setup();
|
||||
|
||||
if (wifi_prov_has_credentials()) {
|
||||
build_status();
|
||||
wifi_ui_show_status();
|
||||
} else {
|
||||
build_setup();
|
||||
wifi_ui_show_setup();
|
||||
set_setup_status("Tap Scan");
|
||||
set_setup_status("Scanning...");
|
||||
/* Defer auto-scan so first frame paints; async so UI stays alive. */
|
||||
g_auto_scan_armed = true;
|
||||
g_auto_scan_at = millis() + 800;
|
||||
}
|
||||
refresh_status_labels();
|
||||
}
|
||||
|
||||
void wifi_ui_show_setup() {
|
||||
if (!scr_setup) {
|
||||
build_setup();
|
||||
}
|
||||
g_on_setup = true;
|
||||
hide_password_dialog();
|
||||
lv_screen_load(scr_setup);
|
||||
}
|
||||
|
||||
void wifi_ui_show_status() {
|
||||
if (!scr_status) {
|
||||
build_status();
|
||||
}
|
||||
g_on_setup = false;
|
||||
hide_password_dialog();
|
||||
refresh_status_labels();
|
||||
@@ -528,14 +588,21 @@ void wifi_ui_show_status() {
|
||||
bool wifi_ui_is_setup() { return g_on_setup; }
|
||||
|
||||
void wifi_ui_tick() {
|
||||
if (g_auto_scan_armed && (int32_t)(millis() - g_auto_scan_at) >= 0) {
|
||||
g_auto_scan_armed = false;
|
||||
do_scan();
|
||||
}
|
||||
|
||||
if (g_scan_pending) {
|
||||
const int n = wifi_prov_scan_poll(g_items, WIFI_PROV_MAX_SCAN);
|
||||
if (n >= 0) {
|
||||
g_scan_pending = false;
|
||||
g_item_n = n;
|
||||
rebuild_list();
|
||||
char buf[40];
|
||||
snprintf(buf, sizeof(buf), "Found %d", g_item_n);
|
||||
char buf[48];
|
||||
const int shown =
|
||||
g_item_n > WIFI_UI_LIST_MAX ? WIFI_UI_LIST_MAX : g_item_n;
|
||||
snprintf(buf, sizeof(buf), "Found %d (top %d)", g_item_n, shown);
|
||||
set_setup_status(buf);
|
||||
}
|
||||
}
|
||||
@@ -555,7 +622,6 @@ void wifi_ui_tick() {
|
||||
}
|
||||
}
|
||||
|
||||
/* Throttle status refresh — every 5ms was wasteful and could feel sticky. */
|
||||
if (!g_on_setup && (millis() - g_last_status_ms >= 500)) {
|
||||
g_last_status_ms = millis();
|
||||
refresh_status_labels();
|
||||
|
||||
Reference in New Issue
Block a user