mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-10-23 06:12:25 +00:00
fix(ui): conversation-row selection on SHORT_CLICKED, not CLICKED
Long-press to delete a conversation, then release: the row fired on_conversation_long_pressed (confirm dialog) AND, on release, on_conversation_clicked, navigating into the conversation and hiding the dialog. Root cause: LVGL 8.4 lv_indev.c indev_proc_release() (lines 973-980) sends LV_EVENT_CLICKED on every pointer release without scrolling, including long-press release — only LV_EVENT_SHORT_CLICKED is gated on long_pr_sent == 0. The row had both CLICKED and LONG_PRESSED bound. Selection is now bound to LV_EVENT_SHORT_CLICKED. Trackball selection is unaffected: the keypad path sends SHORT_CLICKED + CLICKED on a plain enter release and suppresses both when long_pr_sent is set (lv_indev.c:526-531, 678-692). No programmatic CLICKED sends exist in the app. This row is the only object with the CLICKED + LONG_PRESSED double-bind (bubble/textarea long-press sites are single-bound, verified). Contract pins: selection must bind SHORT_CLICKED, no CLICKED binding on the row, long-press delete binding unchanged. 184/184 contracts, tdeck + tdeck-release green.
This commit is contained in:
1 parent
a1c2ec8569
commit
cab2ad8a83
2 files changed
+60
-1
No files matched your search
@@ -532,7 +532,14 @@ void ConversationListScreen::create_conversation_item(const ConversationItem& it
|
||||
// Store peer hash in user data using pool (avoids per-item heap allocations)
|
||||
_peer_hash_pool.push_back(item.peer_hash);
|
||||
lv_obj_set_user_data(container, &_peer_hash_pool.back());
|
||||
lv_obj_add_event_cb(container, on_conversation_clicked, LV_EVENT_CLICKED, this);
|
||||
// SHORT_CLICKED (not CLICKED): in LVGL 8.4 indev_proc_release()
|
||||
// (lv_indev.c:973-980) CLICKED is sent on EVERY pointer release
|
||||
// without scrolling — including a long-press release — while
|
||||
// SHORT_CLICKED is gated on long_pr_sent == 0. With both CLICKED and
|
||||
// LONG_PRESSED bound to the row, a long-press to delete would fire
|
||||
// on_conversation_long_pressed AND, on release, on_conversation_clicked,
|
||||
// navigating into the conversation and hiding the confirm dialog.
|
||||
lv_obj_add_event_cb(container, on_conversation_clicked, LV_EVENT_SHORT_CLICKED, this);
|
||||
lv_obj_add_event_cb(container, on_conversation_long_pressed, LV_EVENT_LONG_PRESSED, this);
|
||||
|
||||
// Track container for focus group management
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Source contract: conversation-row selection must not fire on long-press release.
|
||||
|
||||
LVGL 8.4 lv_indev.c indev_proc_release() (lines ~973-980) sends
|
||||
LV_EVENT_CLICKED on EVERY pointer release without scrolling, including a
|
||||
long-press release — only LV_EVENT_SHORT_CLICKED is gated on
|
||||
long_pr_sent == 0. With both CLICKED and LONG_PRESSED bound to the
|
||||
conversation row, a long-press to open the delete dialog would also, on
|
||||
release, fire the selection handler and navigate into the conversation,
|
||||
hiding the confirm dialog.
|
||||
|
||||
The row therefore binds selection to LV_EVENT_SHORT_CLICKED. Trackball
|
||||
selection is unaffected: the keypad indev path sends SHORT_CLICKED and
|
||||
CLICKED for an enter release without a long press, and suppresses both
|
||||
when long_pr_sent is set.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
LIST_CPP = ROOT / "lib/tdeck_ui/UI/LXMF/ConversationListScreen.cpp"
|
||||
|
||||
|
||||
def _source() -> str:
|
||||
return LIST_CPP.read_text()
|
||||
|
||||
|
||||
def test_row_selection_uses_short_clicked():
|
||||
source = _source()
|
||||
assert (
|
||||
"lv_obj_add_event_cb(container, on_conversation_clicked, LV_EVENT_SHORT_CLICKED, this)"
|
||||
in source
|
||||
), (
|
||||
"conversation row selection must bind LV_EVENT_SHORT_CLICKED — "
|
||||
"LV_EVENT_CLICKED fires on long-press release in LVGL 8.4 and "
|
||||
"would navigate into the chat while the delete dialog is open"
|
||||
)
|
||||
|
||||
|
||||
def test_row_has_no_clicked_binding():
|
||||
source = _source()
|
||||
assert "on_conversation_clicked, LV_EVENT_CLICKED" not in source, (
|
||||
"stale LV_EVENT_CLICKED binding on the conversation row would "
|
||||
"re-introduce the long-press-release navigation"
|
||||
)
|
||||
|
||||
|
||||
def test_row_long_press_delete_binding_unchanged():
|
||||
source = _source()
|
||||
assert (
|
||||
"lv_obj_add_event_cb(container, on_conversation_long_pressed, LV_EVENT_LONG_PRESSED, this)"
|
||||
in source
|
||||
), "long-press delete on the conversation row must remain bound"
|
||||
Reference in new issue
Block a user