diff --git a/components/smart_display/settings_screen.h b/components/smart_display/settings_screen.h index 0a67701..bc7ab83 100644 --- a/components/smart_display/settings_screen.h +++ b/components/smart_display/settings_screen.h @@ -712,8 +712,10 @@ inline void hold_event(lv_event_t *event) { } // A transparent strip over the top bar plus the line that fills while it is held. Both belong to the -// page below, so they survive every redraw of the tiles. -inline void attach_hold(lv_obj_t *page, int x, int y, int width, int height) { +// page below, so they survive every redraw of the tiles. `below` is the first card that opens over the +// page: the strip goes under it, so a card's back button and its action at the top right get their taps +// (firmware 0.2.44-0.2.47 created the strip last, on top of every card). +inline void attach_hold(lv_obj_t *page, int x, int y, int width, int height, lv_obj_t *below = nullptr) { bool large = lv_display_get_horizontal_resolution(lv_display_get_default()) >= 480; hold_area = plain(page, x, y, width, height); lv_obj_add_flag(hold_area, LV_OBJ_FLAG_CLICKABLE); @@ -727,6 +729,10 @@ inline void attach_hold(lv_obj_t *page, int x, int y, int width, int height) { lv_obj_set_style_bg_color(hold_bar, lv_color_hex(0x009FE3), 0); lv_obj_add_flag(hold_bar, LV_OBJ_FLAG_HIDDEN); lv_obj_move_foreground(hold_bar); + if (below && lv_obj_get_parent(below) == page) { + lv_obj_move_to_index(hold_area, lv_obj_get_index(below)); + lv_obj_move_to_index(hold_bar, lv_obj_get_index(below)); + } } } // namespace settings_screen diff --git a/docs/RELEASING.md b/docs/RELEASING.md index bc77692..946518d 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -176,6 +176,19 @@ icons sit off-center in the browser); run `generate_packages.py` afterward. The `MDI_GLYPH_*` substitutions are retired: `TILEn_ICON` in manual profiles must come from the set. No changed preferences or keys. +### Compatibility 0.2.56 / firmware 0.2.48 + +`components/smart_display/settings_screen.h` and both board profiles; the app only raises `FIRMWARE_VERSION`. +Storage, tile protocol, preferences and keys are unchanged. + +- `settings_screen::attach_hold(page, x, y, w, h, below)` moves the hold strip and its fill line to the index of + `below`, directly under it. Both profiles pass `id(brightness_overlay)`, the first of the YAML cards on + `home_page` (brightness, colour, climate, climate mode, then the dim wake overlay). Before, `on_boot` created + the strip after them, so LVGL's hit test found the transparent strip (x 32-448 on the Guition, 72 px high) + before a card's back button (x 16-76) or its action at the top right. The dim wake overlay was not affected: + `apply_screen_settings` moves it to the foreground whenever the screen is dimmed. The runtime detail card + and the settings page move themselves to the foreground and were not affected either. + ### Compatibility 0.2.55 / firmware 0.2.47 App, board profiles and `components/smart_display`. Storage, tile protocol, preferences and keys are unchanged. diff --git a/docs/TEST_RESULTS_0256.md b/docs/TEST_RESULTS_0256.md new file mode 100644 index 0000000..71ebb15 --- /dev/null +++ b/docs/TEST_RESULTS_0256.md @@ -0,0 +1,33 @@ +# Test results app 0.2.56 / firmware 0.2.48 (2026-09-16) + +Max found that the back arrow on the colour card of Studio 1 (firmware 0.2.44) did not respond, while the +card itself kept working. Cause: `settings_screen::attach_hold` (firmware 0.2.44+) creates the transparent +hold strip for the settings page in `on_boot`, after the YAML cards on `home_page`. It therefore lay on top of +them, and LVGL's hit test gave taps in the top bar region (x 32-448, y 0-72 on the Guition) to the strip +instead of the card's back button (x 16-76, y 16-76) or its action at the top right. See CHANGELOG 0.2.56 +and the compatibility note in docs/RELEASING.md. + +## Automated + +- Python (`.venv-portal`): 215 tests OK. `tests/test_settings_page.py` adds + `test_the_hold_strip_lies_under_every_card`: `attach_hold` moves the strip under `below`, both profiles pass + `id(brightness_overlay)`, it is the first card on `home_page` (before colour, climate, climate mode and the + dim wake overlay), and the page controls come before it. +- C++ (`clang++ -std=c++17 -Wall -Wextra -Werror -I. -I components/smart_display`): 14/14 PASS. +- `generate_packages.py --check` green. +- LVGL 9.5 `lv_obj_move_to_index` read in the bundled source: moving the strip and then the fill line to the + index of `brightness_overlay` leaves strip < line < every card in the child order, and the hit test searches + the last child first. + +## Builds (ESPHome 2026.6.2) + +| Profile | RAM | Flash | vs 0.2.55 | +|---|---|---|---| +| easy-guition-device.yaml | 24.0% (78,732 B) | 18.4% (1,496,815 B) | +0 B RAM, +40 B flash | +| easy-cyd-device.yaml | 23.0% (75,484 B) | 76.1% (1,396,847 B) | +0 B RAM, +48 B flash | + +## Not tested / for the owner + +- Hardware and a real LVGL hit test. Nothing was flashed. Studio 1 updates through Home Assistant. On real + glass after the update: the back arrow on the brightness, colour and climate cards, the button at the top + right of the climate card, and holding the top bar on a tile page still opens the settings page. diff --git a/guition-4848s040.yaml b/guition-4848s040.yaml index c179de3..b6801b4 100644 --- a/guition-4848s040.yaml +++ b/guition-4848s040.yaml @@ -2,7 +2,7 @@ # Source profile for packages/guition.yaml (tools/generate_packages.py); see docs/GUITION.md. # A screen gets its tiles from the ESP Screen Manager add-on while it runs. The CYD is its own profile. substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.47" + SCREEN_FIRMWARE_VERSION: "0.2.48" # 0: no drift limit; LVGL decides, releasing inside the tile is a tap, leaving it is not # (like iOS). The CYD keeps a limit because its resistive panel jumps. TOUCH_MOVE_LIMIT_PX: "0" @@ -281,7 +281,9 @@ esphome: settings_screen::before_open = []() { id(close_cards).execute(); }; settings_screen::hold_limit = ${SETTINGS_HOLD_DRIFT_PX}; settings_screen::tap_limit = ${TOUCH_MOVE_LIMIT_PX}; - settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}); + // Under the cards: brightness_overlay is the first of them on the page, so the back button and + // the action at the top right of a card keep their taps. + settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}, id(brightness_overlay)); - light.turn_on: id: back_light brightness: !lambda "return screen_settings::current.brightness / 100.0f;" diff --git a/home-like-2432s028.yaml b/home-like-2432s028.yaml index 281fe29..faf55c0 100644 --- a/home-like-2432s028.yaml +++ b/home-like-2432s028.yaml @@ -17,7 +17,7 @@ ############################################################ substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.47" + SCREEN_FIRMWARE_VERSION: "0.2.48" # A tap survives a finger that drifts up to this far (320 px over 58 mm: 1 cm); further is a swipe. TOUCH_MOVE_LIMIT_PX: "56" # Shortest contact that counts as a tap; a resistive panel bounces, a capacitive one does not. @@ -404,7 +404,9 @@ esphome: settings_screen::before_open = []() { id(close_cards).execute(); }; settings_screen::hold_limit = ${SETTINGS_HOLD_DRIFT_PX}; settings_screen::tap_limit = ${TOUCH_MOVE_LIMIT_PX}; - settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}); + // Under the cards: brightness_overlay is the first of them on the page, so the back button and + // the action at the top right of a card keep their taps. + settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}, id(brightness_overlay)); - light.turn_on: id: back_light brightness: !lambda "return screen_settings::current.brightness / 100.0f;" diff --git a/packages/cyd.yaml b/packages/cyd.yaml index 09e7558..335565b 100644 --- a/packages/cyd.yaml +++ b/packages/cyd.yaml @@ -18,7 +18,7 @@ ############################################################ substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.47" + SCREEN_FIRMWARE_VERSION: "0.2.48" # A tap survives a finger that drifts up to this far (320 px over 58 mm: 1 cm); further is a swipe. TOUCH_MOVE_LIMIT_PX: "56" # Shortest contact that counts as a tap; a resistive panel bounces, a capacitive one does not. @@ -408,7 +408,9 @@ esphome: settings_screen::before_open = []() { id(close_cards).execute(); }; settings_screen::hold_limit = ${SETTINGS_HOLD_DRIFT_PX}; settings_screen::tap_limit = ${TOUCH_MOVE_LIMIT_PX}; - settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}); + // Under the cards: brightness_overlay is the first of them on the page, so the back button and + // the action at the top right of a card keep their taps. + settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}, id(brightness_overlay)); - light.turn_on: id: back_light brightness: !lambda "return screen_settings::current.brightness / 100.0f;" diff --git a/packages/guition.yaml b/packages/guition.yaml index 33000c7..fcfd29e 100644 --- a/packages/guition.yaml +++ b/packages/guition.yaml @@ -3,7 +3,7 @@ # Source profile for packages/guition.yaml (tools/generate_packages.py); see docs/GUITION.md. # A screen gets its tiles from the ESP Screen Manager add-on while it runs. The CYD is its own profile. substitutions: - SCREEN_FIRMWARE_VERSION: "0.2.47" + SCREEN_FIRMWARE_VERSION: "0.2.48" # 0: no drift limit; LVGL decides, releasing inside the tile is a tap, leaving it is not # (like iOS). The CYD keeps a limit because its resistive panel jumps. TOUCH_MOVE_LIMIT_PX: "0" @@ -285,7 +285,9 @@ esphome: settings_screen::before_open = []() { id(close_cards).execute(); }; settings_screen::hold_limit = ${SETTINGS_HOLD_DRIFT_PX}; settings_screen::tap_limit = ${TOUCH_MOVE_LIMIT_PX}; - settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}); + // Under the cards: brightness_overlay is the first of them on the page, so the back button and + // the action at the top right of a card keep their taps. + settings_screen::attach_hold(id(home_page)->obj, ${SETTINGS_HOLD_X}, 0, ${SETTINGS_HOLD_W}, ${SCROLL_Y}, id(brightness_overlay)); - light.turn_on: id: back_light brightness: !lambda "return screen_settings::current.brightness / 100.0f;" diff --git a/screen_manager/CHANGELOG.md b/screen_manager/CHANGELOG.md index 4ee3661..fd87c56 100644 --- a/screen_manager/CHANGELOG.md +++ b/screen_manager/CHANGELOG.md @@ -1,3 +1,10 @@ +## 0.2.56 (firmware 0.2.48) + +The back button on a card works again. + +- **Back works on every card.** Since firmware 0.2.44 the back arrow of the light, colour and climate cards hardly responded, and neither did the button at the top right of the climate card. The invisible strip you hold to open the settings page lay on top of the cards and caught those taps. It now lies under the cards, so holding the top bar only opens the settings page from the tile pages, as intended. +- Needs firmware 0.2.48: press **Update** on the screen. Includes everything from 0.2.55. + ## 0.2.55 (firmware 0.2.47) A colour slider no longer turns red when you let go. diff --git a/screen_manager/app/core.py b/screen_manager/app/core.py index 273f70c..a07c19b 100644 --- a/screen_manager/app/core.py +++ b/screen_manager/app/core.py @@ -17,7 +17,7 @@ WEEKDAYS = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'] REPO = 'https://github.com/MaxGramser/homeassistant_espscreen' REFS = {'cyd': 'main', 'guition': 'main'} # Firmware shipped with this app release; screens below it get an update offer. -FIRMWARE_VERSION = '0.2.47' +FIRMWARE_VERSION = '0.2.48' # The Auto standby switch a screen offers Home Assistant automations. AUTO_STANDBY_MIN_FIRMWARE = '0.2.41' # The settings page the screen opens itself, and the screen.settings tile that opens it. diff --git a/screen_manager/config.yaml b/screen_manager/config.yaml index 460427e..23322e0 100644 --- a/screen_manager/config.yaml +++ b/screen_manager/config.yaml @@ -1,5 +1,5 @@ name: ESP Screen Manager -version: "0.2.55" +version: "0.2.56" slug: esp_screen_manager description: Choose tiles for your CYD and Guition touchscreen, without reflashing. url: https://github.com/MaxGramser/homeassistant_espscreen diff --git a/tests/test_settings_page.py b/tests/test_settings_page.py index 91b417f..febd1a5 100644 --- a/tests/test_settings_page.py +++ b/tests/test_settings_page.py @@ -108,6 +108,22 @@ class Firmware(unittest.TestCase): self.assertGreaterEqual(x, band, name) self.assertLessEqual(x + int(hold), width - band, name) + def test_the_hold_strip_lies_under_every_card(self): + # Firmware 0.2.44-0.2.47 created the strip after the cards, so it lay on top of them: a card's + # back button and its action at the top right lost their taps to it. (The wake overlay of a dimmed + # screen was not affected: apply_screen_settings moves it to the foreground.) + self.assertIn('lv_obj_move_to_index(hold_area, lv_obj_get_index(below));', SCREEN) + cards = ('brightness_overlay', 'color_detail_overlay', 'climate_detail_overlay', 'climate_mode_overlay', + 'dim_wake_overlay') + for name, text in self.profiles.items(): + call = re.search(r'settings_screen::attach_hold\(id\(home_page\)->obj, [^;]*, id\((\w+)\)\);', text) + self.assertTrue(call, f'{name}: attach_hold gets no card to stay under') + self.assertEqual(call[1], cards[0], name) + page = text[text.index('- id: home_page'):] + positions = [page.index(f'id: {card}\n') for card in cards] + self.assertEqual(positions, sorted(positions), f'{name}: {cards[0]} must be the first card on the page') + self.assertLess(page.index('id: page_next\n'), positions[0], f'{name}: the page controls stay under the strip') + if __name__ == '__main__': unittest.main()