ui: make wifi selection usable (#35895)

* start

* wrong

* more

* more

* better

* better

* more better
pull/35910/head
Maxime Desroches 5 days ago committed by GitHub
parent 181ea39a83
commit cccd60a28b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 27
      system/ui/lib/wifi_manager.py
  2. 6
      system/ui/widgets/button.py
  3. 20
      system/ui/widgets/network.py

@ -441,7 +441,6 @@ class WifiManager:
settings_iface.on_connection_removed(self._on_connection_removed) settings_iface.on_connection_removed(self._on_connection_removed)
def _on_properties_changed(self, interface: str, changed: dict, invalidated: list): def _on_properties_changed(self, interface: str, changed: dict, invalidated: list):
# print("property changed", interface, changed, invalidated)
if 'LastScan' in changed: if 'LastScan' in changed:
asyncio.create_task(self._refresh_networks()) asyncio.create_task(self._refresh_networks())
elif interface == NM_WIRELESS_IFACE and "ActiveAccessPoint" in changed: elif interface == NM_WIRELESS_IFACE and "ActiveAccessPoint" in changed:
@ -451,7 +450,6 @@ class WifiManager:
asyncio.create_task(self._refresh_networks()) asyncio.create_task(self._refresh_networks())
def _on_state_changed(self, new_state: int, old_state: int, reason: int): def _on_state_changed(self, new_state: int, old_state: int, reason: int):
print("State changed", new_state, old_state, reason)
if new_state == NMDeviceState.ACTIVATED: if new_state == NMDeviceState.ACTIVATED:
if self.callbacks.activated: if self.callbacks.activated:
self.callbacks.activated() self.callbacks.activated()
@ -461,13 +459,16 @@ class WifiManager:
for network in self.networks: for network in self.networks:
network.is_connected = False network.is_connected = False
# BAD PASSWORD
if new_state == NMDeviceState.NEED_AUTH and reason == NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT and self.callbacks.need_auth: if new_state == NMDeviceState.NEED_AUTH and reason == NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT and self.callbacks.need_auth:
if self._current_connection_ssid: if self._current_connection_ssid:
asyncio.create_task(self.forget_connection(self._current_connection_ssid))
self.callbacks.need_auth(self._current_connection_ssid) self.callbacks.need_auth(self._current_connection_ssid)
else: else:
# Try to find the network from active_ap_path # Try to find the network from active_ap_path
for network in self.networks: for network in self.networks:
if network.path == self.active_ap_path: if network.path == self.active_ap_path:
asyncio.create_task(self.forget_connection(network.ssid))
self.callbacks.need_auth(network.ssid) self.callbacks.need_auth(network.ssid)
break break
else: else:
@ -543,18 +544,28 @@ class WifiManager:
flags = properties['Flags'].value flags = properties['Flags'].value
wpa_flags = properties['WpaFlags'].value wpa_flags = properties['WpaFlags'].value
rsn_flags = properties['RsnFlags'].value rsn_flags = properties['RsnFlags'].value
existing_network = network_dict.get(ssid)
if not existing_network or ((not existing_network.bssid and bssid) or (existing_network.strength < strength)): # May be multiple access points for each SSID. Use first for ssid
# and security type, then update the rest using all APs
if ssid not in network_dict:
network_dict[ssid] = NetworkInfo( network_dict[ssid] = NetworkInfo(
ssid=ssid, ssid=ssid,
strength=strength, strength=0,
security_type=self._get_security_type(flags, wpa_flags, rsn_flags), security_type=self._get_security_type(flags, wpa_flags, rsn_flags),
path=ap_path, path="",
bssid=bssid, bssid="",
is_connected=self.active_ap_path == ap_path and self._current_connection_ssid != ssid, is_connected=False,
is_saved=ssid in self.saved_connections is_saved=ssid in self.saved_connections
) )
existing_network = network_dict.get(ssid)
if existing_network.strength < strength:
existing_network.strength = strength
existing_network.path = ap_path
existing_network.bssid = bssid
if self.active_ap_path == ap_path:
existing_network.is_connected = self._current_connection_ssid != ssid
except DBusError as e: except DBusError as e:
cloudlog.error(f"Error fetching networks: {e}") cloudlog.error(f"Error fetching networks: {e}")
except Exception as e: except Exception as e:

@ -17,6 +17,7 @@ class ButtonStyle(IntEnum):
LIST_ACTION = 5 # For list items with action buttons LIST_ACTION = 5 # For list items with action buttons
NO_EFFECT = 6 NO_EFFECT = 6
KEYBOARD = 7 KEYBOARD = 7
FORGET_WIFI = 8
class TextAlignment(IntEnum): class TextAlignment(IntEnum):
@ -40,6 +41,7 @@ BUTTON_TEXT_COLOR = {
ButtonStyle.LIST_ACTION: rl.Color(228, 228, 228, 255), ButtonStyle.LIST_ACTION: rl.Color(228, 228, 228, 255),
ButtonStyle.NO_EFFECT: rl.Color(228, 228, 228, 255), ButtonStyle.NO_EFFECT: rl.Color(228, 228, 228, 255),
ButtonStyle.KEYBOARD: rl.Color(221, 221, 221, 255), ButtonStyle.KEYBOARD: rl.Color(221, 221, 221, 255),
ButtonStyle.FORGET_WIFI: rl.Color(51, 51, 51, 255),
} }
BUTTON_BACKGROUND_COLORS = { BUTTON_BACKGROUND_COLORS = {
@ -51,6 +53,7 @@ BUTTON_BACKGROUND_COLORS = {
ButtonStyle.LIST_ACTION: rl.Color(57, 57, 57, 255), ButtonStyle.LIST_ACTION: rl.Color(57, 57, 57, 255),
ButtonStyle.NO_EFFECT: rl.Color(51, 51, 51, 255), ButtonStyle.NO_EFFECT: rl.Color(51, 51, 51, 255),
ButtonStyle.KEYBOARD: rl.Color(68, 68, 68, 255), ButtonStyle.KEYBOARD: rl.Color(68, 68, 68, 255),
ButtonStyle.FORGET_WIFI: rl.Color(189, 189, 189, 255),
} }
BUTTON_PRESSED_BACKGROUND_COLORS = { BUTTON_PRESSED_BACKGROUND_COLORS = {
@ -62,6 +65,7 @@ BUTTON_PRESSED_BACKGROUND_COLORS = {
ButtonStyle.LIST_ACTION: rl.Color(74, 74, 74, 74), ButtonStyle.LIST_ACTION: rl.Color(74, 74, 74, 74),
ButtonStyle.NO_EFFECT: rl.Color(51, 51, 51, 255), ButtonStyle.NO_EFFECT: rl.Color(51, 51, 51, 255),
ButtonStyle.KEYBOARD: rl.Color(51, 51, 51, 255), ButtonStyle.KEYBOARD: rl.Color(51, 51, 51, 255),
ButtonStyle.FORGET_WIFI: rl.Color(130, 130, 130, 255),
} }
_pressed_buttons: set[str] = set() # Track mouse press state globally _pressed_buttons: set[str] = set() # Track mouse press state globally
@ -208,7 +212,7 @@ class Button(Widget):
self._background_color = BUTTON_PRESSED_BACKGROUND_COLORS[self._button_style] self._background_color = BUTTON_PRESSED_BACKGROUND_COLORS[self._button_style]
else: else:
self._background_color = BUTTON_BACKGROUND_COLORS[self._button_style] self._background_color = BUTTON_BACKGROUND_COLORS[self._button_style]
else: elif self._button_style != ButtonStyle.NO_EFFECT:
self._background_color = BUTTON_DISABLED_BACKGROUND_COLOR self._background_color = BUTTON_DISABLED_BACKGROUND_COLOR
self._text_color = BUTTON_DISABLED_TEXT_COLOR self._text_color = BUTTON_DISABLED_TEXT_COLOR

@ -41,6 +41,7 @@ class StateConnecting:
@dataclass @dataclass
class StateNeedsAuth: class StateNeedsAuth:
network: NetworkInfo network: NetworkInfo
retry: bool
action: Literal["needs_auth"] = "needs_auth" action: Literal["needs_auth"] = "needs_auth"
@ -93,8 +94,8 @@ class WifiManagerUI(Widget):
return return
match self.state: match self.state:
case StateNeedsAuth(network): case StateNeedsAuth(network, retry):
self.keyboard.set_title("Enter password", f"for {network.ssid}") self.keyboard.set_title("Wrong password" if retry else "Enter password", f"for {network.ssid}")
self.keyboard.reset() self.keyboard.reset()
gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(network, result)) gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(network, result))
case StateShowForgetConfirm(network): case StateShowForgetConfirm(network):
@ -145,16 +146,20 @@ class WifiManagerUI(Widget):
signal_icon_rect = rl.Rectangle(rect.x + rect.width - ICON_SIZE, rect.y + (ITEM_HEIGHT - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE) signal_icon_rect = rl.Rectangle(rect.x + rect.width - ICON_SIZE, rect.y + (ITEM_HEIGHT - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE)
security_icon_rect = rl.Rectangle(signal_icon_rect.x - spacing - ICON_SIZE, rect.y + (ITEM_HEIGHT - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE) security_icon_rect = rl.Rectangle(signal_icon_rect.x - spacing - ICON_SIZE, rect.y + (ITEM_HEIGHT - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE)
self._networks_buttons[network.ssid].render(ssid_rect)
status_text = "" status_text = ""
match self.state: match self.state:
case StateConnecting(network=connecting): case StateConnecting(network=connecting):
if connecting.ssid == network.ssid: if connecting.ssid == network.ssid:
self._networks_buttons[network.ssid].enabled = False
status_text = "CONNECTING..." status_text = "CONNECTING..."
case StateForgetting(network=forgetting): case StateForgetting(network=forgetting):
if forgetting.ssid == network.ssid: if forgetting.ssid == network.ssid:
self._networks_buttons[network.ssid].enabled = False
status_text = "FORGETTING..." status_text = "FORGETTING..."
case _:
self._networks_buttons[network.ssid].enabled = True
self._networks_buttons[network.ssid].render(ssid_rect)
if status_text: if status_text:
status_text_rect = rl.Rectangle(security_icon_rect.x - 410, rect.y, 410, ITEM_HEIGHT) status_text_rect = rl.Rectangle(security_icon_rect.x - 410, rect.y, 410, ITEM_HEIGHT)
@ -176,7 +181,7 @@ class WifiManagerUI(Widget):
def _networks_buttons_callback(self, network): def _networks_buttons_callback(self, network):
if self.scroll_panel.is_touch_valid(): if self.scroll_panel.is_touch_valid():
if not network.is_saved and network.security_type != SecurityType.OPEN: if not network.is_saved and network.security_type != SecurityType.OPEN:
self.state = StateNeedsAuth(network) self.state = StateNeedsAuth(network, False)
elif not network.is_connected: elif not network.is_connected:
self.connect_to_network(network) self.connect_to_network(network)
@ -225,13 +230,14 @@ class WifiManagerUI(Widget):
for n in self._networks: for n in self._networks:
self._networks_buttons[n.ssid] = Button(n.ssid, partial(self._networks_buttons_callback, n), font_size=55, text_alignment=TextAlignment.LEFT, self._networks_buttons[n.ssid] = Button(n.ssid, partial(self._networks_buttons_callback, n), font_size=55, text_alignment=TextAlignment.LEFT,
button_style=ButtonStyle.NO_EFFECT) button_style=ButtonStyle.NO_EFFECT)
self._forget_networks_buttons[n.ssid] = Button("Forget", partial(self._forget_networks_buttons_callback, n), button_style=ButtonStyle.ACTION) self._forget_networks_buttons[n.ssid] = Button("Forget", partial(self._forget_networks_buttons_callback, n), button_style=ButtonStyle.FORGET_WIFI,
font_size=45)
def _on_need_auth(self, ssid): def _on_need_auth(self, ssid):
with self._lock: with self._lock:
network = next((n for n in self._networks if n.ssid == ssid), None) network = next((n for n in self._networks if n.ssid == ssid), None)
if network: if network:
self.state = StateNeedsAuth(network) self.state = StateNeedsAuth(network, True)
def _on_activated(self): def _on_activated(self):
with self._lock: with self._lock:

Loading…
Cancel
Save