Untitled

 avatar
unknown
plain_text
5 months ago
14 kB
3
Indexable
import customtkinter as ctk
import subprocess
import threading
from tkinter import StringVar

class TouchKeyboard(ctk.CTkFrame):
    def __init__(self, master, entry_widget, hide_callback, **kwargs):
        super().__init__(master, **kwargs)
        self.entry = entry_widget
        self.hide_callback = hide_callback
        self.shift_on = False
        
        # Layout settings for the keyboard
        self.layouts = {
            'default': [
                ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
                ['q', 'w', 'e', 'r', 't', 'z', 'u', 'i', 'o', 'p', 'ü'],
                ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'ö', 'ä'],
                ['⇧', 'y', 'x', 'c', 'v', 'b', 'n', 'm', '⌫'],
                ['#+=', ' ', '↵', '⌨']
            ],
            'shift': [
                ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
                ['Q', 'W', 'E', 'R', 'T', 'Z', 'U', 'I', 'O', 'P', 'Ü'],
                ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'Ö', 'Ä'],
                ['⇧', 'Y', 'X', 'C', 'V', 'B', 'N', 'M', '⌫'],
                ['#+=', ' ', '↵', '⌨']
            ],
            'special': [
                ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'],
                ['-', '_', '=', '+', '[', ']', '{', '}', '\\', '|'],
                ['/', ':', ';', '"', '\'', ',', '.', '?', '<', '>'],
                ['ABC', '~', '`', '€', '£', '¥', '§', '⌫'],
                ['123', ' ', '↵', '⌨']
            ]
        }
        self.current_layout = 'default'
        self.create_keyboard()

    def create_keyboard(self):
        # Clear existing buttons
        for widget in self.winfo_children():
            widget.destroy()

        # Create keyboard layout
        layout = self.layouts[self.current_layout]
        
        for row_idx, row in enumerate(layout):
            row_frame = ctk.CTkFrame(self, fg_color="transparent")
            row_frame.grid(row=row_idx, column=0, pady=2)
            
            for col_idx, key in enumerate(row):
                # Determine button width based on key
                width = 65 if key not in ['⌫', '⇧', '#+=', 'ABC', '123', ' ', '↵', '⌨'] else 90
                if key == ' ':
                    width = 200
                
                btn = ctk.CTkButton(
                    row_frame,
                    text=key,
                    width=width,
                    height=50,
                    command=lambda k=key: self.key_press(k)
                )
                btn.grid(row=0, column=col_idx, padx=2)

    def key_press(self, key):
        if key == '⌫':
            current = self.entry.get()
            self.entry.delete(0, 'end')
            self.entry.insert(0, current[:-1])
        elif key == '⇧':
            self.current_layout = 'default' if self.current_layout == 'shift' else 'shift'
            self.create_keyboard()
        elif key == '#+=':
            self.current_layout = 'special'
            self.create_keyboard()
        elif key == 'ABC' or key == '123':
            self.current_layout = 'default'
            self.create_keyboard()
        elif key == '↵':
            # Enter key functionality
            pass
        elif key == '⌨':
            self.hide_callback()
        else:
            current_pos = self.entry.index('insert')
            self.entry.insert(current_pos, key)

class WifiConfiguratorApp(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title("Wi-Fi Configurator")
        self.geometry("1024x600")
        self.resizable(False, False)
        
        # Variables
        self.networks = []
        self.selected_network = StringVar()
        self.password = StringVar()
        self.show_password = ctk.BooleanVar(value=False)
        self.keyboard_visible = False
        self.current_connection = {
            "SSID": "Not connected",
            "Signal Strength": "N/A",
            "IP Address": "N/A"
        }
        self.status_message = StringVar(value="Idle")
        
        # Create main container
        self.main_container = ctk.CTkFrame(self)
        self.main_container.pack(fill="both", expand=True)
        
        # Create UI Elements
        self.create_widgets()
        self.scan_wifi_networks()
        self.update_current_connection()

    def create_widgets(self):
        # Top section (always visible)
        self.top_frame = ctk.CTkFrame(self.main_container)
        self.top_frame.pack(fill="x", padx=20, pady=10)

        # Title and Status
        title_label = ctk.CTkLabel(
            self.top_frame, 
            text="Wi-Fi Configurator",
            font=("Arial", 32, "bold")
        )
        title_label.pack(pady=(10, 5))

        self.status_label = ctk.CTkLabel(
            self.top_frame,
            textvariable=self.status_message,
            font=("Arial", 16)
        )
        self.status_label.pack(pady=5)

        # Content section
        self.content_frame = ctk.CTkFrame(self.main_container)
        self.content_frame.pack(fill="both", expand=True, padx=20)

        # Network selection
        network_label = ctk.CTkLabel(
            self.content_frame,
            text="Select Network:",
            font=("Arial", 16)
        )
        network_label.pack(pady=(20, 5))

        self.network_dropdown = ctk.CTkOptionMenu(
            self.content_frame,
            variable=self.selected_network,
            values=self.networks,
            width=300,
            height=40
        )
        self.network_dropdown.pack(pady=5)

        # Password entry
        password_label = ctk.CTkLabel(
            self.content_frame,
            text="Password:",
            font=("Arial", 16)
        )
        password_label.pack(pady=(20, 5))

        self.password_entry = ctk.CTkEntry(
            self.content_frame,
            textvariable=self.password,
            show="*",
            width=300,
            height=40
        )
        self.password_entry.pack(pady=5)
        self.password_entry.bind("<FocusIn>", self.show_keyboard)

        # Connection info (collapsible)
        self.connection_frame = ctk.CTkFrame(self.content_frame)
        self.connection_frame.pack(fill="x", pady=20)

        self.ssid_label = ctk.CTkLabel(
            self.connection_frame,
            text="SSID: Not connected",
            font=("Arial", 14)
        )
        self.ssid_label.pack(pady=2)

        self.signal_label = ctk.CTkLabel(
            self.connection_frame,
            text="Signal Strength: N/A",
            font=("Arial", 14)
        )
        self.signal_label.pack(pady=2)

        self.ip_label = ctk.CTkLabel(
            self.connection_frame,
            text="IP Address: N/A",
            font=("Arial", 14)
        )
        self.ip_label.pack(pady=2)

        # Action buttons
        button_frame = ctk.CTkFrame(self.content_frame)
        button_frame.pack(pady=20)

        ctk.CTkButton(
            button_frame,
            text="Connect",
            command=self.start_connecting_to_wifi,
            width=120,
            height=40
        ).grid(row=0, column=0, padx=10)

        ctk.CTkButton(
            button_frame,
            text="Refresh",
            command=self.scan_wifi_networks,
            width=120,
            height=40
        ).grid(row=0, column=1, padx=10)

        # Keyboard container (hidden initially)
        self.keyboard_frame = ctk.CTkFrame(self.main_container)
        self.keyboard = TouchKeyboard(
            self.keyboard_frame,
            self.password_entry,
            self.hide_keyboard,
            fg_color="transparent"
        )
        self.keyboard.pack(pady=10)

    def show_keyboard(self, event=None):
        if not self.keyboard_visible:
            self.connection_frame.pack_forget()  # Hide connection info
            self.keyboard_frame.pack(fill="x", padx=20, pady=10)
            self.keyboard_visible = True

    def hide_keyboard(self):
        if self.keyboard_visible:
            self.keyboard_frame.pack_forget()
            self.connection_frame.pack(fill="x", pady=20)  # Show connection info
            self.keyboard_visible = False

    def update_status_appearance(self):
        message = self.status_message.get().lower()
        if "success" in message or "connected" in message:
            self.status_label.configure(text_color="green")
        elif "error" in message or "failed" in message or "incorrect" in message:
            self.status_label.configure(text_color="red")
        else:
            self.status_label.configure(text_color="gray")

    # Keep all existing methods for WiFi functionality
    def scan_wifi_networks(self):
        self.status_message.set("Scanning for Wi-Fi networks...")
        self.update_status_appearance()
        threading.Thread(target=self._scan_wifi_networks_thread).start()

    def _scan_wifi_networks_thread(self):
        try:
            result = subprocess.run(
                ["nmcli", "-t", "-f", "SSID,SIGNAL", "dev", "wifi"],
                capture_output=True, text=True
            )
            if result.returncode == 0:
                networks = []
                for line in result.stdout.split("\n"):
                    if line and line.split(":")[0]:
                        ssid, _ = line.split(":")
                        if ssid and ssid not in networks:
                            networks.append(ssid)

                self.networks = networks
                self.network_dropdown.configure(values=self.networks)
                if self.networks:
                    self.selected_network.set(self.networks[0])
                self.status_message.set("Wi-Fi scan completed.")
            else:
                self.status_message.set("Failed to scan Wi-Fi networks.")
            self.update_status_appearance()
        except Exception as e:
            self.status_message.set(f"Error: {e}")
            self.update_status_appearance()

    def start_connecting_to_wifi(self):
        threading.Thread(target=self.connect_to_wifi).start()

    def connect_to_wifi(self):
        ssid = self.selected_network.get()
        password = self.password.get()

        if not ssid:
            self.status_message.set("Please select a Wi-Fi network.")
            self.update_status_appearance()
            return

        self.status_message.set(f"Connecting to {ssid}...")
        self.update_status_appearance()

        try:
            result = subprocess.run(
                ["nmcli", "dev", "wifi", "connect", ssid, "password", password],
                capture_output=True, text=True
            )
            if result.returncode == 0:
                self.status_message.set(f"Successfully connected to {ssid}.")
                self.update_current_connection()
            else:
                error_message = result.stderr.strip()
                if "802-11-wireless-security.psk: property is invalid" in error_message:
                    self.status_message.set("Incorrect password. Please try again.")
                elif "No network with SSID" in error_message:
                    self.status_message.set("The selected Wi-Fi network is unavailable.")
                else:
                    self.status_message.set(f"Connection failed: {error_message}")
                self.password.set("")
            self.update_status_appearance()
        except Exception as e:
            self.status_message.set(f"Error: {e}")
            self.update_status_appearance()

    def update_current_connection(self):
        try:
            ssid_result = subprocess.run(
                ["nmcli", "-t", "-f", "ACTIVE,SSID,SIGNAL", "dev", "wifi"],
                capture_output=True, text=True
            )
            ip_result = subprocess.run(
                ["hostname", "-I"], capture_output=True, text=True
            )

            if ssid_result.returncode == 0:
                for line in ssid_result.stdout.split("\n"):
                    if line.startswith("yes"):
                        _, ssid, signal = line.split(":")
                        self.current_connection["SSID"] = ssid
                        self.current_connection["Signal Strength"] = f"{signal}%"
                        break
                else:
                    self.current_connection["SSID"] = "Not connected"
                    self.current_connection["Signal Strength"] = "N/A"

            if ip_result.returncode == 0:
                self.current_connection["IP Address"] = ip_result.stdout.strip()
            else:
                self.current_connection["IP Address"] = "N/A"

            self.ssid_label.configure(text=f"SSID: {self.current_connection['SSID']}")
            self.signal_label.configure(text=f"Signal Strength: {self.current_connection['Signal Strength']}")
            self.ip_label.configure(text=f"IP Address: {self.current_connection['IP Address']}")

        except Exception as e:
            self.status_message.set(f"Failed to retrieve connection details: {e}")
            self.update_status_appearance()

if __name__ == "__main__":
    ctk.set_appearance_mode("Dark")  # Modern dark theme
    ctk.set_default_color_theme("blue")
    
    app = WifiConfiguratorApp()
    app.mainloop()
Editor is loading...
Leave a Comment