From 5290f8b4f03c29c704c38bb213b6700f5d3496e6 Mon Sep 17 00:00:00 2001 From: Lago Date: Fri, 3 Apr 2026 21:30:05 +0200 Subject: [PATCH] fix: FTP passive mode, battery UI position, SD path traversal - Add ftpSrv.setLocalIp() for correct PASV response IP (fixes transfers) - Move battery indicator to WiFi SSID line, right-aligned - Fix battery label tilt: fixed width + LV_TEXT_ALIGN_RIGHT - Fix calcDirSize: use f.path() for full path in recursive walk --- src/main.cpp | 10 ++++++--- src/ui.cpp | 57 ++++++++++++++++++++++++++++------------------------ 2 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index e47bc31..cff6c3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,9 +108,10 @@ static uint64_t calcDirSize(fs::FS &fs, const char *dirname) { File f; while ((f = root.openNextFile())) { if (f.isDirectory()) { - String path = f.name(); + /* On ESP32 Arduino 3.x, f.path() returns the full path */ + String fullPath = String(f.path()); f.close(); - total += calcDirSize(fs, path.c_str()); + total += calcDirSize(fs, fullPath.c_str()); } else { total += f.size(); f.close(); @@ -442,8 +443,11 @@ static void initFtp() { Serial.println("[FTP] Starting FTP server (user: kode, port: 21)..."); ftpSrv.setCallback(ftpCallback); ftpSrv.setTransferCallback(ftpTransferCallback); + /* Set local IP so PASV mode sends the correct address to clients */ + ftpSrv.setLocalIp(WiFi.localIP()); ftpSrv.begin("kode", "kode"); - Serial.println("[FTP] FTP server ready"); + Serial.printf("[FTP] FTP server ready (PASV IP: %s, data port: 50009)\n", + WiFi.localIP().toString().c_str()); ui_set_ftp("Idle"); } diff --git a/src/ui.cpp b/src/ui.cpp index 8e07a16..55bc65d 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -80,32 +80,6 @@ void ui_init() LV_ALIGN_TOP_MID, 0, 16, "FTP Explorer"); lv_obj_set_style_text_letter_space(lbl_title, 2, 0); - /* ── battery indicator (top-right) ─────────────────────────── */ - /* battery outline (22x12 rounded rect) */ - obj_batt_icon = lv_obj_create(scr); - lv_obj_set_size(obj_batt_icon, 30, 14); - lv_obj_set_style_radius(obj_batt_icon, 3, 0); - lv_obj_set_style_bg_opa(obj_batt_icon, LV_OPA_TRANSP, 0); - lv_obj_set_style_border_color(obj_batt_icon, lv_color_hex(CLR_GRAY), 0); - lv_obj_set_style_border_width(obj_batt_icon, 1, 0); - lv_obj_set_style_pad_all(obj_batt_icon, 2, 0); - lv_obj_clear_flag(obj_batt_icon, LV_OBJ_FLAG_SCROLLABLE); - lv_obj_align(obj_batt_icon, LV_ALIGN_TOP_RIGHT, -28, 22); - - /* battery fill bar (inside the outline) */ - obj_batt_fill = lv_obj_create(obj_batt_icon); - lv_obj_set_size(obj_batt_fill, 0, 8); - lv_obj_set_style_radius(obj_batt_fill, 1, 0); - lv_obj_set_style_bg_color(obj_batt_fill, lv_color_hex(CLR_GREEN), 0); - lv_obj_set_style_bg_opa(obj_batt_fill, LV_OPA_COVER, 0); - lv_obj_set_style_border_width(obj_batt_fill, 0, 0); - lv_obj_clear_flag(obj_batt_fill, LV_OBJ_FLAG_SCROLLABLE); - lv_obj_align(obj_batt_fill, LV_ALIGN_LEFT_MID, 0, 0); - - /* battery percentage text */ - lbl_battery = make_label(scr, &lv_font_montserrat_12, CLR_GRAY, - LV_ALIGN_TOP_RIGHT, -62, 23, "--"); - /* subtle separator line */ static lv_point_precise_t line_pts[] = {{40, 0}, {370, 0}}; line_sep = lv_line_create(scr); @@ -122,6 +96,37 @@ void ui_init() LV_ALIGN_TOP_LEFT, 28, 68, LV_SYMBOL_WIFI " Disconnected"); + /* ── battery indicator (same line as WiFi, right-aligned) ──── */ + /* battery percentage text — fixed width to prevent 45° tilt */ + lbl_battery = lv_label_create(scr); + lv_label_set_text(lbl_battery, "--"); + lv_obj_set_style_text_font(lbl_battery, &lv_font_montserrat_16, 0); + lv_obj_set_style_text_color(lbl_battery, lv_color_hex(CLR_GRAY), 0); + lv_obj_set_width(lbl_battery, 90); + lv_obj_set_style_text_align(lbl_battery, LV_TEXT_ALIGN_RIGHT, 0); + lv_obj_align(lbl_battery, LV_ALIGN_TOP_RIGHT, -48, 68); + + /* battery outline (30x14 rounded rect) */ + obj_batt_icon = lv_obj_create(scr); + lv_obj_set_size(obj_batt_icon, 30, 14); + lv_obj_set_style_radius(obj_batt_icon, 3, 0); + lv_obj_set_style_bg_opa(obj_batt_icon, LV_OPA_TRANSP, 0); + lv_obj_set_style_border_color(obj_batt_icon, lv_color_hex(CLR_GRAY), 0); + lv_obj_set_style_border_width(obj_batt_icon, 1, 0); + lv_obj_set_style_pad_all(obj_batt_icon, 2, 0); + lv_obj_clear_flag(obj_batt_icon, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_align(obj_batt_icon, LV_ALIGN_TOP_RIGHT, -16, 69); + + /* battery fill bar (inside the outline) */ + obj_batt_fill = lv_obj_create(obj_batt_icon); + lv_obj_set_size(obj_batt_fill, 0, 8); + lv_obj_set_style_radius(obj_batt_fill, 1, 0); + lv_obj_set_style_bg_color(obj_batt_fill, lv_color_hex(CLR_GREEN), 0); + lv_obj_set_style_bg_opa(obj_batt_fill, LV_OPA_COVER, 0); + lv_obj_set_style_border_width(obj_batt_fill, 0, 0); + lv_obj_clear_flag(obj_batt_fill, LV_OBJ_FLAG_SCROLLABLE); + lv_obj_align(obj_batt_fill, LV_ALIGN_LEFT_MID, 0, 0); + lbl_ip = make_label(scr, &lv_font_montserrat_30, CLR_CYAN, LV_ALIGN_TOP_LEFT, 28, 96, "0.0.0.0");