# -*- coding: utf-8 -*- """ F2: Netzwerk-Konfiguration — WiFi-Hotspot, WLAN-Verbindung, Server-Verbindung. """ from __future__ import annotations from textual.widgets import Checkbox, Input, Label, RadioButton, RadioSet, Static from .base import InstallerView class NetworkView(InstallerView): """Netzwerk-Einstellungen (F2).""" TITLE = "Netzwerk" VIEW_ID = "network" MODES = ["server", "client", "standalone"] def compose(self): if self._config.mode == "server": yield from self._compose_server() elif self._config.mode == "client": yield from self._compose_wifi_connect() yield from self._compose_client() elif self._config.mode == "standalone": yield from self._compose_wifi_connect() def _compose_server(self): """Server: WiFi-Hotspot Konfiguration.""" yield Static("── WiFi-Hotspot ──", classes="section-header") yield Checkbox( "WiFi-Hotspot aktivieren", value=self._config.wifi_enabled, id="cb-wifi-enabled", ) yield Label("") yield Label("SSID:") yield Input( value=self._config.wifi_ssid, placeholder="z.B. trixyone_srv", id="input-wifi-ssid", ) yield Label("Passwort (min. 8 Zeichen):") yield Input( value=self._config.wifi_password, placeholder="WiFi-Passwort", id="input-wifi-password", password=True, ) yield Label("Kanal (1-13):") yield Input( value=str(self._config.wifi_channel), placeholder="6", id="input-wifi-channel", ) yield Label("Access-Point IP:") yield Input( value=self._config.ap_ip, placeholder="10.10.10.1", id="input-ap-ip", ) yield Label("DHCP-Bereich Start:") yield Input( value=self._config.dhcp_range_start, placeholder="10.10.10.10", id="input-dhcp-start", ) yield Label("DHCP-Bereich Ende:") yield Input( value=self._config.dhcp_range_end, placeholder="10.10.10.50", id="input-dhcp-end", ) def _compose_wifi_connect(self): """Client/Standalone: WLAN-Verbindung konfigurieren.""" yield Static("── WLAN-Verbindung ──", classes="section-header") yield RadioSet( RadioButton( "Keine Aenderung — bestehendes WLAN beibehalten", value=not self._config.wifi_connect, id="rb-wifi-keep", ), RadioButton( "WLAN konfigurieren — mit Netzwerk verbinden", value=self._config.wifi_connect, id="rb-wifi-connect", ), id="rs-wifi-connect", ) yield Label("") yield Static("[dim]Primaeres Netz (bevorzugt, z.B. Trixy-Server-Hotspot)[/dim]") yield Label("SSID:") yield Input( value=self._config.wifi_connect_ssid, placeholder="z.B. trixyone_srv", id="input-wifi-connect-ssid", disabled=not self._config.wifi_connect, ) yield Label("Passwort:") yield Input( value=self._config.wifi_connect_password, placeholder="WLAN-Passwort", id="input-wifi-connect-password", password=True, disabled=not self._config.wifi_connect, ) yield Label("") yield Checkbox( "Fallback-WLAN aktivieren (z.B. Heim-WLAN)", value=self._config.wifi_fallback_enabled, id="cb-wifi-fallback", disabled=not self._config.wifi_connect, ) yield Static( "[dim]Wird genutzt wenn das primaere Netz nicht erreichbar ist[/dim]" ) yield Label("Fallback-SSID:") yield Input( value=self._config.wifi_fallback_ssid, placeholder="z.B. FRITZ!Box 7590", id="input-wifi-fallback-ssid", disabled=not (self._config.wifi_connect and self._config.wifi_fallback_enabled), ) yield Label("Fallback-Passwort:") yield Input( value=self._config.wifi_fallback_password, placeholder="Fallback-WLAN-Passwort", id="input-wifi-fallback-password", password=True, disabled=not (self._config.wifi_connect and self._config.wifi_fallback_enabled), ) yield Label("") yield Checkbox( "Auto-Rueckwechsel zum primaeren Netz", value=self._config.wifi_auto_switchback, id="cb-wifi-switchback", disabled=not (self._config.wifi_connect and self._config.wifi_fallback_enabled), ) yield Static( "[dim]Prueft regelmaessig ob primaeres Netz wieder erreichbar ist[/dim]" ) yield Label("Pruef-Intervall (Sekunden):") yield Input( value=str(self._config.wifi_switchback_interval), placeholder="30", id="input-wifi-switchback-interval", disabled=not ( self._config.wifi_connect and self._config.wifi_fallback_enabled and self._config.wifi_auto_switchback ), ) yield Label("") def _compose_client(self): """Client: Server-Verbindung.""" yield Static("── Server-Verbindung ──", classes="section-header") yield Label("Server-Host:") yield Input( value=self._config.server_host, placeholder="z.B. 10.10.10.1", id="input-server-host", ) yield Label("Server-Port:") yield Input( value=str(self._config.server_port), placeholder="2101", id="input-server-port", ) yield Label("Raum:") yield Input( value=self._config.room, placeholder="z.B. Wohnzimmer", id="input-room", ) yield Label("Alias:") yield Input( value=self._config.alias, placeholder="z.B. Patrick", id="input-alias", ) def _update_wifi_field_states(self) -> None: """Aktualisiert disabled-Status der WLAN-Eingabefelder.""" connect = self._config.wifi_connect fallback = self._config.wifi_fallback_enabled switchback = self._config.wifi_auto_switchback field_states = { "#input-wifi-connect-ssid": not connect, "#input-wifi-connect-password": not connect, "#cb-wifi-fallback": not connect, "#input-wifi-fallback-ssid": not (connect and fallback), "#input-wifi-fallback-password": not (connect and fallback), "#cb-wifi-switchback": not (connect and fallback), "#input-wifi-switchback-interval": not (connect and fallback and switchback), } for selector, disabled in field_states.items(): try: widget = self.query_one(selector) widget.disabled = disabled except Exception: pass def on_radio_set_changed(self, event: RadioSet.Changed) -> None: """WLAN-Modus umschalten.""" if event.radio_set.id == "rs-wifi-connect": pressed_id = event.pressed.id if event.pressed else "" self._config.wifi_connect = pressed_id == "rb-wifi-connect" self._update_wifi_field_states() def on_input_changed(self, event: Input.Changed) -> None: """Aktualisiert Konfig bei Eingabeaenderungen.""" mapping = { "input-wifi-ssid": "wifi_ssid", "input-wifi-password": "wifi_password", "input-ap-ip": "ap_ip", "input-dhcp-start": "dhcp_range_start", "input-dhcp-end": "dhcp_range_end", "input-wifi-connect-ssid": "wifi_connect_ssid", "input-wifi-connect-password": "wifi_connect_password", "input-wifi-fallback-ssid": "wifi_fallback_ssid", "input-wifi-fallback-password": "wifi_fallback_password", "input-server-host": "server_host", "input-room": "room", "input-alias": "alias", } attr = mapping.get(event.input.id or "") if attr: setattr(self._config, attr, event.value) elif event.input.id == "input-wifi-channel": try: self._config.wifi_channel = int(event.value) except ValueError: pass elif event.input.id == "input-server-port": try: self._config.server_port = int(event.value) except ValueError: pass elif event.input.id == "input-wifi-switchback-interval": try: self._config.wifi_switchback_interval = int(event.value) except ValueError: pass def on_checkbox_changed(self, event: Checkbox.Changed) -> None: cb_id = event.checkbox.id or "" if cb_id == "cb-wifi-enabled": self._config.wifi_enabled = event.value elif cb_id == "cb-wifi-fallback": self._config.wifi_fallback_enabled = event.value self._update_wifi_field_states() elif cb_id == "cb-wifi-switchback": self._config.wifi_auto_switchback = event.value self._update_wifi_field_states() def validate(self) -> str | None: if self._config.mode == "server" and self._config.wifi_enabled: if not self._config.wifi_ssid.strip(): return "WiFi SSID darf nicht leer sein" if len(self._config.wifi_password) < 8: return "WiFi Passwort muss mindestens 8 Zeichen haben" elif self._config.mode == "client": if not self._config.server_host.strip(): return "Server-Host darf nicht leer sein" if not self._config.room.strip(): return "Raum darf nicht leer sein" if not self._config.alias.strip(): return "Alias darf nicht leer sein" # WLAN-Validierung (Client/Standalone) if self._config.wifi_connect: if not self._config.wifi_connect_ssid.strip(): return "Primaere WLAN-SSID darf nicht leer sein" if len(self._config.wifi_connect_password) < 8: return "Primaeres WLAN-Passwort muss mindestens 8 Zeichen haben" if self._config.wifi_fallback_enabled: if not self._config.wifi_fallback_ssid.strip(): return "Fallback-WLAN-SSID darf nicht leer sein" if len(self._config.wifi_fallback_password) < 8: return "Fallback-WLAN-Passwort muss mindestens 8 Zeichen haben" if self._config.wifi_fallback_ssid.strip() == self._config.wifi_connect_ssid.strip(): return "Fallback- und primaere SSID muessen unterschiedlich sein" if self._config.wifi_switchback_interval < 10: return "Switchback-Intervall muss mindestens 10 Sekunden sein" return None