mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-04-07 13:54:00 +08:00
WifiUi: add new networks to end, delete buttons on exit (#37189)
* add networks to end, remove bad scroller restore logic that sometimes starts in the middle * works * almost * wifi slash * clean up * clean up * opactiy * more clean up * more clean up * set enabled and network missing on regain network * cmt
This commit is contained in:
@@ -36,20 +36,29 @@ class WifiIcon(Widget):
|
||||
super().__init__()
|
||||
self.set_rect(rl.Rectangle(0, 0, 86, 64))
|
||||
|
||||
self._wifi_slash_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_slash.png", 86, 64)
|
||||
self._wifi_low_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_low.png", 86, 64)
|
||||
self._wifi_medium_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_medium.png", 86, 64)
|
||||
self._wifi_full_txt = gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 86, 64)
|
||||
self._lock_txt = gui_app.texture("icons_mici/settings/network/new/lock.png", 22, 32)
|
||||
|
||||
self._network: Network | None = None
|
||||
self._network_missing = False # if network disappeared from scan results
|
||||
self._scale = 1.0
|
||||
self._opacity = 1.0
|
||||
|
||||
def set_current_network(self, network: Network):
|
||||
self._network = network
|
||||
|
||||
def set_network_missing(self, missing: bool):
|
||||
self._network_missing = missing
|
||||
|
||||
def set_scale(self, scale: float):
|
||||
self._scale = scale
|
||||
|
||||
def set_opacity(self, opacity: float):
|
||||
self._opacity = opacity
|
||||
|
||||
@staticmethod
|
||||
def get_strength_icon_idx(strength: int) -> int:
|
||||
return round(strength / 100 * 2)
|
||||
@@ -60,23 +69,26 @@ class WifiIcon(Widget):
|
||||
|
||||
# Determine which wifi strength icon to use
|
||||
strength = self.get_strength_icon_idx(self._network.strength)
|
||||
if strength == 2:
|
||||
if self._network_missing:
|
||||
strength_icon = self._wifi_slash_txt
|
||||
elif strength == 2:
|
||||
strength_icon = self._wifi_full_txt
|
||||
elif strength == 1:
|
||||
strength_icon = self._wifi_medium_txt
|
||||
else:
|
||||
strength_icon = self._wifi_low_txt
|
||||
|
||||
tint = rl.Color(255, 255, 255, int(255 * self._opacity))
|
||||
icon_x = int(self._rect.x + (self._rect.width - strength_icon.width * self._scale) // 2)
|
||||
icon_y = int(self._rect.y + (self._rect.height - strength_icon.height * self._scale) // 2)
|
||||
rl.draw_texture_ex(strength_icon, (icon_x, icon_y), 0.0, self._scale, rl.WHITE)
|
||||
rl.draw_texture_ex(strength_icon, (icon_x, icon_y), 0.0, self._scale, tint)
|
||||
|
||||
# Render lock icon at lower right of wifi icon if secured
|
||||
if self._network.security_type not in (SecurityType.OPEN, SecurityType.UNSUPPORTED):
|
||||
lock_scale = self._scale * 1.1
|
||||
lock_x = int(icon_x + 1 + strength_icon.width * self._scale - self._lock_txt.width * lock_scale / 2)
|
||||
lock_y = int(icon_y + 1 + strength_icon.height * self._scale - self._lock_txt.height * lock_scale / 2)
|
||||
rl.draw_texture_ex(self._lock_txt, (lock_x, lock_y), 0.0, lock_scale, rl.WHITE)
|
||||
rl.draw_texture_ex(self._lock_txt, (lock_x, lock_y), 0.0, lock_scale, tint)
|
||||
|
||||
|
||||
class WifiItem(BigDialogOptionButton):
|
||||
@@ -93,16 +105,26 @@ class WifiItem(BigDialogOptionButton):
|
||||
self._wifi_icon = WifiIcon()
|
||||
self._wifi_icon.set_current_network(network)
|
||||
|
||||
def set_network_missing(self, missing: bool):
|
||||
self._wifi_icon.set_network_missing(missing)
|
||||
|
||||
def set_current_network(self, network: Network):
|
||||
self._network = network
|
||||
self._wifi_icon.set_current_network(network)
|
||||
|
||||
# reset if we see the network again
|
||||
self.set_enabled(True)
|
||||
self.set_network_missing(False)
|
||||
|
||||
def _render(self, _):
|
||||
disabled_alpha = 0.35 if not self.enabled else 1.0
|
||||
|
||||
if self._network.is_connected:
|
||||
selected_x = int(self._rect.x - self._selected_txt.width / 2)
|
||||
selected_y = int(self._rect.y + (self._rect.height - self._selected_txt.height) / 2)
|
||||
rl.draw_texture(self._selected_txt, selected_x, selected_y, rl.WHITE)
|
||||
|
||||
self._wifi_icon.set_opacity(disabled_alpha)
|
||||
self._wifi_icon.set_scale((1.0 if self._selected else 0.65) * 0.7)
|
||||
self._wifi_icon.render(rl.Rectangle(
|
||||
self._rect.x + self.LEFT_MARGIN,
|
||||
@@ -113,11 +135,11 @@ class WifiItem(BigDialogOptionButton):
|
||||
|
||||
if self._selected:
|
||||
self._label.set_font_size(self.SELECTED_HEIGHT)
|
||||
self._label.set_color(rl.Color(255, 255, 255, int(255 * 0.9)))
|
||||
self._label.set_color(rl.Color(255, 255, 255, int(255 * 0.9 * disabled_alpha)))
|
||||
self._label.set_font_weight(FontWeight.DISPLAY)
|
||||
else:
|
||||
self._label.set_font_size(self.HEIGHT)
|
||||
self._label.set_color(rl.Color(255, 255, 255, int(255 * 0.58)))
|
||||
self._label.set_color(rl.Color(255, 255, 255, int(255 * 0.58 * disabled_alpha)))
|
||||
self._label.set_font_weight(FontWeight.DISPLAY_REGULAR)
|
||||
|
||||
label_offset = self.LEFT_MARGIN + self._wifi_icon.rect.width + 20
|
||||
@@ -314,9 +336,6 @@ class NetworkInfoPage(NavWidget):
|
||||
|
||||
|
||||
class WifiUIMici(BigMultiOptionDialog):
|
||||
# Wait this long after user interacts with widget to update network list
|
||||
INACTIVITY_TIMEOUT = 1
|
||||
|
||||
def __init__(self, wifi_manager: WifiManager, back_callback: Callable):
|
||||
super().__init__([], None)
|
||||
|
||||
@@ -332,10 +351,6 @@ class WifiUIMici(BigMultiOptionDialog):
|
||||
self._connecting: str | None = None
|
||||
self._networks: dict[str, Network] = {}
|
||||
|
||||
# widget state
|
||||
self._last_interaction_time = -float('inf')
|
||||
self._restore_selection = False
|
||||
|
||||
self._wifi_manager.add_callbacks(
|
||||
need_auth=self._on_need_auth,
|
||||
activated=self._on_activated,
|
||||
@@ -348,11 +363,12 @@ class WifiUIMici(BigMultiOptionDialog):
|
||||
# Call super to prepare scroller; selection scroll is handled dynamically
|
||||
super().show_event()
|
||||
self._wifi_manager.set_active(True)
|
||||
self._last_interaction_time = -float('inf')
|
||||
|
||||
def hide_event(self):
|
||||
super().hide_event()
|
||||
self._wifi_manager.set_active(False)
|
||||
# clear scroller items to remove old networks on next show
|
||||
self._scroller._items.clear()
|
||||
|
||||
def _open_network_manage_page(self, result=None):
|
||||
self._network_info_page.update_networks(self._networks)
|
||||
@@ -372,27 +388,28 @@ class WifiUIMici(BigMultiOptionDialog):
|
||||
self._network_info_page.update_networks(self._networks)
|
||||
|
||||
def _update_buttons(self):
|
||||
# Don't update buttons while user is actively interacting
|
||||
if rl.get_time() - self._last_interaction_time < self.INACTIVITY_TIMEOUT:
|
||||
return
|
||||
# Only add new buttons to the end. Update existing buttons without re-sorting so user can freely scroll around
|
||||
|
||||
for network in self._networks.values():
|
||||
# pop and re-insert to eliminate stuttering on update (prevents position lost for a frame)
|
||||
network_button_idx = next((i for i, btn in enumerate(self._scroller._items) if btn.option == network.ssid), None)
|
||||
if network_button_idx is not None:
|
||||
network_button = self._scroller._items.pop(network_button_idx)
|
||||
# Update network on existing button
|
||||
network_button.set_current_network(network)
|
||||
self._scroller._items[network_button_idx].set_current_network(network)
|
||||
else:
|
||||
network_button = WifiItem(network)
|
||||
self._scroller.add_widget(network_button)
|
||||
|
||||
self._scroller.add_widget(network_button)
|
||||
# Move connected network to the start
|
||||
connected_btn_idx = next((i for i, btn in enumerate(self._scroller._items) if btn._network.is_connected), None)
|
||||
if connected_btn_idx is not None and connected_btn_idx > 0:
|
||||
self._scroller._items.insert(0, self._scroller._items.pop(connected_btn_idx))
|
||||
self._scroller._layout() # fixes selected style single frame stutter
|
||||
|
||||
# remove networks no longer present
|
||||
self._scroller._items[:] = [btn for btn in self._scroller._items if btn.option in self._networks]
|
||||
|
||||
# try to restore previous selection to prevent jumping from adding/removing/reordering buttons
|
||||
self._restore_selection = True
|
||||
# Disable networks no longer present
|
||||
for btn in self._scroller._items:
|
||||
if btn.option not in self._networks:
|
||||
btn.set_enabled(False)
|
||||
btn.set_network_missing(True)
|
||||
|
||||
def _connect_with_password(self, ssid: str, password: str):
|
||||
if password:
|
||||
@@ -440,19 +457,7 @@ class WifiUIMici(BigMultiOptionDialog):
|
||||
def _on_disconnected(self):
|
||||
self._connecting = None
|
||||
|
||||
def _update_state(self):
|
||||
super()._update_state()
|
||||
if self.is_pressed:
|
||||
self._last_interaction_time = rl.get_time()
|
||||
|
||||
def _render(self, _):
|
||||
# Update Scroller layout and restore current selection whenever buttons are updated, before first render
|
||||
current_selection = self.get_selected_option()
|
||||
if self._restore_selection and current_selection in self._networks:
|
||||
self._scroller._layout()
|
||||
BigMultiOptionDialog._on_option_selected(self, current_selection)
|
||||
self._restore_selection = None
|
||||
|
||||
super()._render(_)
|
||||
|
||||
if not self._networks:
|
||||
|
||||
Reference in New Issue
Block a user