import asyncio
import pyray as rl
from enum import IntEnum
from dbus_next . constants import MessageType
from openpilot . system . ui . lib . wifi_manager import WifiManager , NetworkInfo
from openpilot . system . ui . lib . application import gui_app
from openpilot . system . ui . lib . button import gui_button
from openpilot . system . ui . lib . label import gui_label
from openpilot . system . ui . lib . scroll_panel import GuiScrollPanel
from openpilot . system . ui . widgets . keyboard import Keyboard
from openpilot . system . ui . widgets . confirm_dialog import confirm_dialog
NM_DEVICE_STATE_NEED_AUTH = 60
class ActionState ( IntEnum ) :
NONE = 0
CONNECT = 1
CONNECTING = 2
FORGOT = 3
FORGETTING = 4
NEED_AUTH = 5
SHOW_FORGOT_CONFIRM = 6
class WifiManagerUI :
def __init__ ( self , wifi_manager ) :
self . wifi_manager = wifi_manager
self . wifi_manager . need_auth_callback = self . _need_auth
self . _selected_network = None
self . item_height = 160
self . btn_width = 200
self . current_action : ActionState = ActionState . NONE
self . scroll_panel = GuiScrollPanel ( )
self . keyboard = Keyboard ( )
asyncio . create_task ( self . _initialize ( ) )
async def _initialize ( self ) - > None :
try :
await self . wifi_manager . connect ( )
except Exception as e :
print ( f " Initialization error: { e } " )
def render ( self , rect : rl . Rectangle ) :
if not self . wifi_manager . networks :
gui_label ( rect , " Scanning Wi-Fi networks... " , 40 , alignment = rl . GuiTextAlignment . TEXT_ALIGN_CENTER )
return
if self . current_action == ActionState . SHOW_FORGOT_CONFIRM :
result = confirm_dialog ( rect , f ' Forget Wi-Fi Network " { self . _selected_network . ssid } " ? ' , ' Forget ' )
if result == 1 :
asyncio . create_task ( self . forgot_network ( ) )
elif result == 0 :
self . current_action = ActionState . NONE
return
if self . current_action == ActionState . NEED_AUTH :
result = self . keyboard . render ( rect , ' Enter password ' , f ' for { self . _selected_network . ssid } ' )
if result == 0 :
return
elif result == 1 :
self . current_action = ActionState . NONE
asyncio . create_task ( self . connect_to_network ( self . keyboard . text ) )
else :
self . current_action = ActionState . NONE
return
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 ) * self . item_height
)
offset = self . scroll_panel . handle_scroll ( rect , content_rect )
rl . begin_scissor_mode ( int ( rect . x ) , int ( rect . y ) , int ( rect . width ) , int ( rect . height ) )
clicked = offset . y < 10 and rl . is_mouse_button_released ( rl . MouseButton . MOUSE_BUTTON_LEFT )
for i , network in enumerate ( self . wifi_manager . networks ) :
y_offset = i * self . item_height + offset . y
item_rect = rl . Rectangle ( rect . x , y_offset , rect . width , self . item_height )
if rl . check_collision_recs ( item_rect , rect ) :
self . _draw_network_item ( item_rect , network , clicked )
if i < len ( self . wifi_manager . 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
)
rl . end_scissor_mode ( )
def _draw_network_item ( self , rect , network : NetworkInfo , clicked : bool ) :
label_rect = rl . Rectangle ( rect . x , rect . y , rect . width - self . btn_width * 2 , self . item_height )
state_rect = rl . Rectangle (
rect . x + rect . width - self . btn_width * 2 - 150 , rect . y , 300 , self . item_height
)
gui_label ( label_rect , network . ssid , 55 )
if network . is_connected and self . current_action == ActionState . NONE :
rl . gui_label ( state_rect , " Connected " )
elif (
self . current_action == " Connecting "
and self . _selected_network
and self . _selected_network . ssid == network . ssid
) :
rl . gui_label ( state_rect , " CONNECTING... " )
# If the network is saved, show the "Forget" button
if self . wifi_manager . is_saved ( network . ssid ) :
forget_btn_rect = rl . Rectangle (
rect . x + rect . width - self . btn_width ,
rect . y + ( self . item_height - 80 ) / 2 ,
self . btn_width ,
80 ,
)
if gui_button ( forget_btn_rect , " Forget " ) and self . current_action == ActionState . NONE :
self . _selected_network = network
self . current_action = ActionState . SHOW_FORGOT_CONFIRM
if (
self . current_action == ActionState . NONE
and rl . check_collision_point_rec ( rl . get_mouse_position ( ) , label_rect )
and clicked
) :
self . _selected_network = network
if not self . wifi_manager . is_saved ( self . _selected_network . ssid ) :
self . current_action = ActionState . NEED_AUTH
else :
asyncio . create_task ( self . connect_to_network ( ) )
async def forgot_network ( self ) :
self . current_action = ActionState . FORGETTING
await self . wifi_manager . forgot_connection ( self . _selected_network . ssid )
self . current_action = ActionState . NONE
async def connect_to_network ( self , password = ' ' ) :
self . current_action = ActionState . CONNECTING
if self . wifi_manager . is_saved ( self . _selected_network . ssid ) and not password :
await self . wifi_manager . activate_connection ( self . _selected_network . ssid )
else :
await self . wifi_manager . connect_to_network ( self . _selected_network . ssid , password )
self . current_action = ActionState . NONE
def _need_auth ( self ) :
self . current_action = ActionState . NEED_AUTH
async def main ( ) :
gui_app . init_window ( " Wifi Manager " )
wifi_manager = WifiManager ( )
wifi_ui = WifiManagerUI ( wifi_manager )
while not rl . window_should_close ( ) :
rl . begin_drawing ( )
rl . clear_background ( rl . BLACK )
wifi_ui . render ( rl . Rectangle ( 50 , 50 , gui_app . width - 100 , gui_app . height - 100 ) )
rl . end_drawing ( )
await asyncio . sleep ( 0.001 )
if __name__ == " __main__ " :
asyncio . run ( main ( ) )