From 471fde78c11d618c7ff5e0ce2d67fc1938f44de570f316bade7434f9d1c8572e Mon Sep 17 00:00:00 2001 From: AidarKC Date: Tue, 9 Jun 2026 18:30:12 +0400 Subject: [PATCH] =?UTF-8?q?ESP32:=20=D1=83=D0=B6=D0=B5=D1=81=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=B8=D1=82=D1=8C=20touch=20UX=20=D0=B8=20=D0=BE=D0=B1?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B8=D1=82=D1=8C=20=D0=B8=D0=BD=D1=81=D1=82?= =?UTF-8?q?=D1=80=D1=83=D0=BA=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 7 ++++ .../2026-06-08_1940_esp32_nav_minimal_test.md | 5 ++- .../shine_subserver_ui_nav_minimal_spec.md | 5 ++- .../lvgl_nav_minimal_test.ino | 37 +++++++++++++++---- VERSION.properties | 4 +- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index e7f7464..c1bc31e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -24,6 +24,13 @@ - Подробные служебные правила Telegram-обработчика, его очередь, история, systemd-запуск и особенности ответов описывать в `SHiNE-agent-bot-coder/AGENT.md`. - Если в сообщениях пользователя встречается «агент MD» или похожая формулировка про файл инструкций Codex, считать, что имеется в виду автоматически читаемый `AGENTS.md`. +## ESP32 UI сабсервера +- Для UI-скетча устройства `ESP32-S3-Touch-AMOLED-2.16` документ-спецификация и Arduino-скетч должны всегда оставаться синхронными. +- Актуальный документ по экранной логике, состояниям, кнопкам, полям, статусам и ограничениям UI считать источником истины для скетча. +- При изменении документа обязательно в том же наборе изменений приводить в соответствие скетч. +- При изменении скетча обязательно в том же наборе изменений обновлять документ, если поменялись экраны, тексты, переходы, статусы, кнопки, поля или поведение. +- Для нового ESP32 UI-прототипа сабсервера использовать русский язык как основной и отдельно следить, чтобы текст реально отображался на устройстве, а не только логически присутствовал в коде. + ## Solana-модуль - В проекте есть отдельный Solana/Anchor-модуль в папке `shine-solana/shine/`. - Модуль логически связан с SHiNE, но не должен автоматически подключаться к сборке или деплою основного сервера без отдельного решения. diff --git a/Dev_Docs/Pending_Features/2026-06-08_1940_esp32_nav_minimal_test.md b/Dev_Docs/Pending_Features/2026-06-08_1940_esp32_nav_minimal_test.md index 1590067..77f147b 100644 --- a/Dev_Docs/Pending_Features/2026-06-08_1940_esp32_nav_minimal_test.md +++ b/Dev_Docs/Pending_Features/2026-06-08_1940_esp32_nav_minimal_test.md @@ -34,7 +34,10 @@ - визуальный курсор в поле ввода не показывается; - новые символы всегда дописываются только в конец строки; - основные 3 ряда клавиш и нижний служебный ряд стали выше; - - внизу остаётся отдельная тёмная полоса с версией `NAV v7`, а рамка клавиатурного блока заканчивается выше неё; + - внизу остаётся отдельная тёмная полоса с версией `SHiNE subserver (v.0.18)`, а рамка клавиатурного блока заканчивается выше неё; + - одно непрерывное касание вызывает не более одного действия кнопки; + - скольжение пальцем по клавиатуре не нажимает подряд несколько клавиш; + - медленный свайп по экрану не должен превращаться в случайное нажатие кнопки; - `ABC/123`, `SHIFT`, `DEL`, `SAVE`, `CANCEL` работают; - при успехе SSID и пароль сохраняются, а `HOME` показывает `Wi-Fi connected`; - при ошибке показывается `Connection failed`; diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/reference/shine_subserver_ui_nav_minimal_spec.md b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/reference/shine_subserver_ui_nav_minimal_spec.md index b1e6810..9e1198f 100644 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/reference/shine_subserver_ui_nav_minimal_spec.md +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/reference/shine_subserver_ui_nav_minimal_spec.md @@ -253,7 +253,7 @@ - `DEL` - `SAVE` - `CANCEL` -- ниже рамки клавиатурного блока остаётся отдельная тёмная полоса с версией `NAV v7`. +- ниже рамки клавиатурного блока остаётся отдельная тёмная полоса с версией `SHiNE subserver (v.0.18)`. ## Жесты @@ -279,6 +279,9 @@ - если палец ушёл из зоны обычного тапа и жест определяется как свайп, случайное попадание на кнопку по пути не должно превращать свайп в нажатие; - приоритет у свайпа, а не у `click`. +- одно непрерывное касание может вызвать не более одного действия кнопки; +- скольжение пальцем по экранной клавиатуре не должно вызывать цепочку из нескольких нажатий; +- периодический refresh на `HOME` не должен срабатывать во время активного касания. ## Язык diff --git a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_nav_minimal_test/lvgl_nav_minimal_test.ino b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_nav_minimal_test/lvgl_nav_minimal_test.ino index 60bed92..4e30667 100644 --- a/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_nav_minimal_test/lvgl_nav_minimal_test.ino +++ b/ESP32/esp32/ESP32-S3-Touch-AMOLED-2.16/test-device/test_sketches/lvgl_nav_minimal_test/lvgl_nav_minimal_test.ino @@ -137,6 +137,9 @@ static int16_t gTouchLastX = 0; static int16_t gTouchLastY = 0; static SwipeDirection gPendingSwipe = SWIPE_NONE; static bool gBlockClick = false; +static bool gSuppressTouchUntilRelease = false; +static uint32_t gTouchSequence = 0; +static uint32_t gLastHandledTouchSequence = 0; static String gWifiSavedSsid; static String gWifiSavedPassword; @@ -257,13 +260,23 @@ static void lvglTouchRead(lv_indev_drv_t *indevDrv, lv_indev_data_t *data) { if (touching) { if (!gTouchDown) { gTouchDown = true; + gTouchSequence++; gTouchStartX = x; gTouchStartY = y; + gBlockClick = false; + gSuppressTouchUntilRelease = false; } gTouchLastX = x; gTouchLastY = y; if (movedTooFarForTap(gTouchStartX, gTouchStartY, gTouchLastX, gTouchLastY)) { gBlockClick = true; + gSuppressTouchUntilRelease = true; + } + if (gSuppressTouchUntilRelease) { + data->state = LV_INDEV_STATE_REL; + data->point.x = gTouchLastX; + data->point.y = gTouchLastY; + return; } data->state = LV_INDEV_STATE_PR; data->point.x = x; @@ -274,11 +287,11 @@ static void lvglTouchRead(lv_indev_drv_t *indevDrv, lv_indev_data_t *data) { if (gTouchDown) { gTouchDown = false; gPendingSwipe = detectSwipe(gTouchStartX, gTouchStartY, gTouchLastX, gTouchLastY); - if (gPendingSwipe == SWIPE_NONE && !movedTooFarForTap(gTouchStartX, gTouchStartY, gTouchLastX, gTouchLastY)) { - gBlockClick = false; - } } + gSuppressTouchUntilRelease = false; + gBlockClick = false; + data->state = LV_INDEV_STATE_REL; data->point.x = gTouchLastX; data->point.y = gTouchLastY; @@ -800,9 +813,12 @@ static void restoreTextareaFromEditValue() { } static void networkSelectCb(lv_event_t *event) { - if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick || gLastHandledTouchSequence == gTouchSequence) { return; } + gLastHandledTouchSequence = gTouchSequence; + gSuppressTouchUntilRelease = true; + gBlockClick = true; int index = static_cast(reinterpret_cast(lv_event_get_user_data(event))); if (index < 0 || index >= gScanResultCount) { @@ -819,9 +835,12 @@ static void networkSelectCb(lv_event_t *event) { } static void editorKeyCb(lv_event_t *event) { - if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick || !gInputTextArea) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick || gLastHandledTouchSequence == gTouchSequence || !gInputTextArea) { return; } + gLastHandledTouchSequence = gTouchSequence; + gSuppressTouchUntilRelease = true; + gBlockClick = true; const char *token = static_cast(lv_event_get_user_data(event)); if (!token) { @@ -874,9 +893,12 @@ static void editorKeyCb(lv_event_t *event) { } static void actionButtonCb(lv_event_t *event) { - if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick) { + if (lv_event_get_code(event) != LV_EVENT_CLICKED || gBlockClick || gLastHandledTouchSequence == gTouchSequence) { return; } + gLastHandledTouchSequence = gTouchSequence; + gSuppressTouchUntilRelease = true; + gBlockClick = true; ActionId action = static_cast(reinterpret_cast(lv_event_get_user_data(event))); switch (action) { @@ -1665,7 +1687,7 @@ void loop() { manageWifiReconnect(); static unsigned long lastHomeRefreshMs = 0; - if (gCurrentScreen == SCREEN_HOME && millis() - lastHomeRefreshMs >= 1000) { + if (gCurrentScreen == SCREEN_HOME && !gTouchDown && millis() - lastHomeRefreshMs >= 1000) { lastHomeRefreshMs = millis(); rebuildScreen(); } @@ -1690,7 +1712,6 @@ void loop() { SwipeDirection swipe = gPendingSwipe; gPendingSwipe = SWIPE_NONE; handleSwipe(swipe); - gBlockClick = false; } delay(5); diff --git a/VERSION.properties b/VERSION.properties index 6de14c8..16ffc1e 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.146 -server.version=1.2.138 +client.version=1.2.147 +server.version=1.2.139