From 099143ad9df14de601ed95a694b0fc3e55f20503 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Wed, 5 Aug 2026 23:22:36 -0400 Subject: [PATCH] [mici] ui: fix swipe-down in sunnylink and models panels (#1896) * [mici] ui: fix swipe-down in sunnylink and models panels * update mici replay test * [mici] ui: push model sub-views as separate widgets for correct back navigation --- .../ui/sunnypilot/mici/layouts/models.py | 32 +++++++------------ .../ui/sunnypilot/mici/layouts/settings.py | 4 +-- .../ui/sunnypilot/mici/layouts/sunnylink.py | 4 +-- .../selfdrive/ui/tests/diff/replay_script.py | 3 ++ 4 files changed, 18 insertions(+), 25 deletions(-) diff --git a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/models.py b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/models.py index 8999281430..af8f348f72 100644 --- a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/models.py +++ b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/models.py @@ -4,7 +4,6 @@ Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ -from collections.abc import Callable import pyray as rl from openpilot.cereal import custom @@ -48,10 +47,8 @@ class CurrentModelInfo(Widget): self.info_text.render() class ModelsLayoutMici(NavScroller): - def __init__(self, back_callback: Callable): + def __init__(self): super().__init__() - self.set_back_callback(back_callback) - self.original_back_callback = back_callback self.focused_widget = None self.current_model_info = CurrentModelInfo() @@ -85,12 +82,10 @@ class ModelsLayoutMici(NavScroller): return folders - def _show_selection_view(self, items, back_callback: Callable): - self._scroller._items = items - for item in items: - item.set_touch_valid_callback(lambda: self._scroller.scroll_panel.is_touch_valid() and self._scroller.enabled) - self._scroller.scroll_panel.set_offset(0) - self.set_back_callback(back_callback) + def _push_selection_view(self, items): + scroller = NavScroller() + scroller._scroller.add_widgets(items) + gui_app.push_widget(scroller) def _show_folders(self): self.focused_widget = self.select_model_btn @@ -112,15 +107,18 @@ class ModelsLayoutMici(NavScroller): folder_buttons.insert(0, btn) else: folder_buttons.append(btn) - self._show_selection_view(folder_buttons, self._reset_main_view) + self._push_selection_view(folder_buttons) + + def _pop_to_main(self): + gui_app.pop_widgets_to(self) def _select_model(self, bundle): ui_state.params.put("ModelManager_DownloadIndex", bundle.index) - self._reset_main_view() + self._pop_to_main() def _select_default(self): ui_state.params.remove("ModelManager_ActiveBundle") - self._reset_main_view() + self._pop_to_main() def _select_folder(self, folder_name): favs = ui_state.params.get("ModelManager_Favs") @@ -135,13 +133,7 @@ class ModelsLayoutMici(NavScroller): btn = BigButton(txt) btn.set_click_callback(lambda b=bundle: self._select_model(b)) btns.append(btn) - self._show_selection_view(btns, self._show_folders) - - def _reset_main_view(self): - self._scroller._items = self.main_items # type: ignore[assignment] # ty: ignore[invalid-assignment] - self.set_back_callback(self.original_back_callback) - self._scroller.scroll_panel.set_offset(0) - self._scroller.scroll_to(0) + self._push_selection_view(btns) def hide_event(self): super().hide_event() diff --git a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/settings.py b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/settings.py index 96a4c789c1..f14efe51a3 100644 --- a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/settings.py +++ b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/settings.py @@ -32,11 +32,11 @@ class SettingsLayoutSP(OP.SettingsLayout): BIG_ICON_SIZE) self.icon_offroad_slider = gui_app.texture("icons_mici/settings/device/lkas.png", BIG_ICON_SIZE, BIG_ICON_SIZE) - sunnylink_panel = SunnylinkLayoutMici(back_callback=gui_app.pop_widget) + sunnylink_panel = SunnylinkLayoutMici() sunnylink_btn = SettingsBigButton(tr("sunnylink"), "", gui_app.texture("icons_mici/settings/developer/ssh.png", 55, 55)) sunnylink_btn.set_click_callback(lambda: gui_app.push_widget(sunnylink_panel)) - models_panel = ModelsLayoutMici(back_callback=gui_app.pop_widget) + models_panel = ModelsLayoutMici() models_btn = SettingsBigButton(tr("models"), "", gui_app.texture("../../sunnypilot/selfdrive/assets/offroad/icon_models.png", ICON_SIZE, ICON_SIZE)) models_btn.set_click_callback(lambda: gui_app.push_widget(models_panel)) diff --git a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/sunnylink.py b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/sunnylink.py index e804c78035..7c42f99f83 100644 --- a/openpilot/selfdrive/ui/sunnypilot/mici/layouts/sunnylink.py +++ b/openpilot/selfdrive/ui/sunnypilot/mici/layouts/sunnylink.py @@ -6,7 +6,6 @@ See the LICENSE.md file in the root directory for more details. """ import pyray as rl -from collections.abc import Callable from openpilot.cereal import custom from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigToggle @@ -54,9 +53,8 @@ class SunnylinkInfo(Widget): self.sponsor_text.render() class SunnylinkLayoutMici(NavScroller): - def __init__(self, back_callback: Callable): + def __init__(self): super().__init__() - self.set_back_callback(back_callback) self._restore_in_progress = False self._backup_in_progress = False self._sunnylink_enabled = ui_state.params.get("SunnylinkEnabled") diff --git a/openpilot/selfdrive/ui/tests/diff/replay_script.py b/openpilot/selfdrive/ui/tests/diff/replay_script.py index 109f32e47a..18f3141fa1 100644 --- a/openpilot/selfdrive/ui/tests/diff/replay_script.py +++ b/openpilot/selfdrive/ui/tests/diff/replay_script.py @@ -338,8 +338,11 @@ def build_mici_script(pm: PubMaster, main_layout, script: Script) -> None: settings_cases: Cases = [ lambda: scroll_through_cases(toggle_cases), + None, # sunnylink (just open and close) + None, # models (just open and close) lambda: scroll_through_cases(network_cases), lambda: scroll_through_cases(device_cases), + lambda: script.wait(WAIT_SHORT), # software lambda: script.wait(WAIT_SHORT), # pairing lambda: run_actions(lambda: swipe_up(height * 3), lambda: swipe_down(height * 3)), # firehose (scroll down and back up) lambda: scroll_through_cases(developer_cases),