From f62f465958dcfa4a0e2e0041ed30db706c146e1d Mon Sep 17 00:00:00 2001 From: Torlando <281092095+torlando-agent[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 05:52:56 +0000 Subject: [PATCH] fix(settings): don't auto-scroll to bottom on screen entry LVGL re-focuses the default input group when the screen is shown; the focused member is the last focusable object (the transport switch), so the view landed at the bottom of the list. A one-shot 50ms LVGL timer after show() scrolls the content back to the top without touching the focus state, and leaves subsequent user scrolling alone. --- lib/tdeck_ui/UI/LXMF/SettingsScreen.cpp | 28 +++++++++++++++++++++++++ lib/tdeck_ui/UI/LXMF/SettingsScreen.h | 2 ++ 2 files changed, 30 insertions(+) diff --git a/lib/tdeck_ui/UI/LXMF/SettingsScreen.cpp b/lib/tdeck_ui/UI/LXMF/SettingsScreen.cpp index 968ddba4..02d3a72e 100644 --- a/lib/tdeck_ui/UI/LXMF/SettingsScreen.cpp +++ b/lib/tdeck_ui/UI/LXMF/SettingsScreen.cpp @@ -17,6 +17,14 @@ using namespace RNS; namespace UI { namespace LXMF { +// One-shot scroll reset: when LVGL re-focuses the default input group on +// screen entry it scrolls the view to the focused member (the last +// focusable object — the transport switch), which lands the user at the +// bottom of the list. A short delay after show() puts the view back at the +// top; later scrolling is left to the user. +static SettingsScreen* g_settings_entry_reset = nullptr; +lv_timer_t* SettingsScreen::_entry_scroll_reset_timer = nullptr; + // NVS keys static const char* NVS_NAMESPACE = "settings"; static const char* KEY_WIFI_SSID = "wifi_ssid"; @@ -1401,6 +1409,17 @@ void SettingsScreen::set_status_callback(StatusScreenCallback callback) { _status_callback = callback; } +void SettingsScreen::entry_scroll_reset_cb(lv_timer_t* timer) { + lv_timer_del(timer); + SettingsScreen* screen = g_settings_entry_reset; + g_settings_entry_reset = nullptr; + if (!screen || !screen->_content) return; + LVGL_LOCK(); + if (lv_obj_is_visible(screen->_screen)) { + lv_obj_scroll_to_y(screen->_content, 0, LV_ANIM_OFF); + } +} + void SettingsScreen::show() { LVGL_LOCK(); lv_obj_clear_flag(_screen, LV_OBJ_FLAG_HIDDEN); @@ -1417,6 +1436,15 @@ void SettingsScreen::show() { lv_group_focus_obj(_btn_back); } } + + // Counter the group re-focus auto-scroll (see entry_scroll_reset_cb). + // show() already holds the LVGL lock, so timer creation here is safe. + g_settings_entry_reset = this; + if (!_entry_scroll_reset_timer) { + _entry_scroll_reset_timer = lv_timer_create(entry_scroll_reset_cb, 50, nullptr); + } else { + lv_timer_reset(_entry_scroll_reset_timer); + } } void SettingsScreen::hide() { diff --git a/lib/tdeck_ui/UI/LXMF/SettingsScreen.h b/lib/tdeck_ui/UI/LXMF/SettingsScreen.h index 0f71b105..c12ecc2b 100644 --- a/lib/tdeck_ui/UI/LXMF/SettingsScreen.h +++ b/lib/tdeck_ui/UI/LXMF/SettingsScreen.h @@ -340,6 +340,8 @@ private: static void on_transport_cancel_enable(lv_event_t* event); void show_transport_warning(); void close_transport_warning(); + static lv_timer_t* _entry_scroll_reset_timer; + static void entry_scroll_reset_cb(lv_timer_t* timer); }; } // namespace LXMF