From f1760e63d39d1be2ed470364e435b2cd981c8e45 Mon Sep 17 00:00:00 2001 From: Dean Lee Date: Sun, 11 May 2025 15:26:25 +0800 Subject: [PATCH] system/ui: performance optimizations for WiFi Manager with cached network data (#35170) Performance optimizations for WiFi Manager with cached network data --- system/ui/lib/wifi_manager.py | 15 ++++++++++----- system/ui/widgets/network.py | 22 ++++++++++++++-------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py index 29d3231d5f..00649b146b 100644 --- a/system/ui/lib/wifi_manager.py +++ b/system/ui/lib/wifi_manager.py @@ -1,5 +1,6 @@ import asyncio import concurrent.futures +import copy import threading import time import uuid @@ -56,6 +57,7 @@ class NetworkInfo: security_type: SecurityType path: str bssid: str + is_saved: bool = False # saved_path: str @@ -64,6 +66,7 @@ class WifiManagerCallbacks: need_auth: Callable[[str], None] | None = None activated: Callable[[], None] | None = None forgotten: Callable[[], None] | None = None + networks_updated: Callable[[list[NetworkInfo]], None] | None = None class WifiManager: @@ -452,6 +455,8 @@ class WifiManager: del self.saved_connections[ssid] if self.callbacks.forgotten: self.callbacks.forgotten() + # Update network list to reflect the removed saved connection + asyncio.create_task(self._update_connection_status()) break async def _add_saved_connection(self, path: str) -> None: @@ -460,6 +465,7 @@ class WifiManager: settings = await self._get_connection_settings(path) if ssid := self._extract_ssid(settings): self.saved_connections[ssid] = path + await self._update_connection_status() except DBusError as e: cloudlog.error(f"Failed to add connection {path}: {e}") @@ -517,6 +523,7 @@ class WifiManager: path=ap_path, bssid=bssid, is_connected=self.active_ap_path == ap_path, + is_saved=ssid in self.saved_connections ) except DBusError as e: @@ -533,6 +540,9 @@ class WifiManager: ), ) + if self.callbacks.networks_updated: + self.callbacks.networks_updated(copy.deepcopy(self.networks)) + async def _get_connection_settings(self, path): """Fetch connection settings for a specific connection path.""" try: @@ -628,11 +638,6 @@ class WifiManagerWrapper: self._thread.join(timeout=2.0) self._running = False - @property - def networks(self) -> list[NetworkInfo]: - """Get the current list of networks.""" - return self._run_coroutine_sync(lambda manager: manager.networks.copy(), default=[]) - def is_saved(self, ssid: str) -> bool: """Check if a network is saved.""" return self._run_coroutine_sync(lambda manager: manager.is_saved(ssid), default=False) diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py index 0e9ad349b6..14f4017925 100644 --- a/system/ui/widgets/network.py +++ b/system/ui/widgets/network.py @@ -48,13 +48,15 @@ class WifiManagerUI: self.scroll_panel = GuiScrollPanel() self.keyboard = Keyboard() + self._networks: list[NetworkInfo] = [] + self.wifi_manager = wifi_manager - self.wifi_manager.set_callbacks(WifiManagerCallbacks(self._on_need_auth, self._on_activated, self._on_forgotten)) + self.wifi_manager.set_callbacks(WifiManagerCallbacks(self._on_need_auth, self._on_activated, self._on_forgotten, self._on_network_updated)) self.wifi_manager.start() self.wifi_manager.connect() def render(self, rect: rl.Rectangle): - if not self.wifi_manager.networks: + if not self._networks: gui_label(rect, "Scanning Wi-Fi networks...", 72, alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER) return @@ -77,19 +79,19 @@ class WifiManagerUI: self._draw_network_list(rect) def _draw_network_list(self, rect: rl.Rectangle): - content_rect = rl.Rectangle(rect.x, rect.y, rect.width, len(self.wifi_manager.networks) * ITEM_HEIGHT) + content_rect = rl.Rectangle(rect.x, rect.y, rect.width, len(self._networks) * ITEM_HEIGHT) offset = self.scroll_panel.handle_scroll(rect, content_rect) clicked = self.scroll_panel.is_click_valid() rl.begin_scissor_mode(int(rect.x), int(rect.y), int(rect.width), int(rect.height)) - for i, network in enumerate(self.wifi_manager.networks): + for i, network in enumerate(self._networks): y_offset = rect.y + i * ITEM_HEIGHT + offset.y item_rect = rl.Rectangle(rect.x, y_offset, rect.width, ITEM_HEIGHT) if not rl.check_collision_recs(item_rect, rect): continue self._draw_network_item(item_rect, network, clicked) - if i < len(self.wifi_manager.networks) - 1: + if i < len(self._networks) - 1: line_y = int(item_rect.y + item_rect.height - 1) rl.draw_line(int(item_rect.x), int(line_y), int(item_rect.x + item_rect.width), line_y, rl.LIGHTGRAY) @@ -115,7 +117,7 @@ class WifiManagerUI: rl.gui_label(state_rect, status_text) # If the network is saved, show the "Forget" button - if self.wifi_manager.is_saved(network.ssid): + if network.is_saved: forget_btn_rect = rl.Rectangle( rect.x + rect.width - self.btn_width, rect.y + (ITEM_HEIGHT - 80) / 2, @@ -126,22 +128,26 @@ class WifiManagerUI: self.state = StateShowForgetConfirm(network) if isinstance(self.state, StateIdle) and rl.check_collision_point_rec(rl.get_mouse_position(), label_rect) and clicked: - if not self.wifi_manager.is_saved(network.ssid): + if not network.is_saved: self.state = StateNeedsAuth(network) else: self.connect_to_network(network) def connect_to_network(self, network: NetworkInfo, password=''): self.state = StateConnecting(network) - if self.wifi_manager.is_saved(network.ssid) and not password: + if network.is_saved and not password: self.wifi_manager.activate_connection(network.ssid) else: self.wifi_manager.connect_to_network(network.ssid, password) def forget_network(self, network: NetworkInfo): self.state = StateForgetting(network) + network.is_saved = False self.wifi_manager.forget_connection(network.ssid) + def _on_network_updated(self, networks: list[NetworkInfo]): + self._networks = networks + def _on_need_auth(self, ssid): match self.state: case StateConnecting(ssid):