Untitled

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

class ToastNotification(ctk.CTkFrame):
    def __init__(self, parent, message_type="info", **kwargs):
        super().__init__(parent, fg_color="transparent", **kwargs)
        
        # Define colors for different message types
        self.colors = {
            "success": "#34C759",
            "error": "#FF3B30",
            "warning": "#FF9F0A",
            "info": "#0A84FF"
        }
        
        # Define icons for different message types
        self.icons = {
            "success": "✓",
            "error": "×",
            "warning": "⚠",
            "info": "ℹ"
        }
        
        # Create toast container
        self.toast = ctk.CTkFrame(
            self,
            fg_color=self.colors.get(message_type, self.colors["info"]),
            corner_radius=8,
            height=40
        )
        self.toast.pack(fill="x", padx=20, pady=10)
        
        # Add icon
        self.icon_label = ctk.CTkLabel(
            self.toast,
            text=self.icons.get(message_type, ""),
            font=("SF Pro Display", 18, "bold"),
            text_color="white",
            width=30
        )
        self.icon_label.pack(side="left", padx=(15, 5))
        
        # Add message
        self.message_label = ctk.CTkLabel(
            self.toast,
            text="",
            font=("SF Pro Display", 14),
            text_color="white"
        )
        self.message_label.pack(side="left", padx=(5, 15), fill="x", expand=True)
        
        self.place(relx=0.5, rely=-0.2, anchor="n", relwidth=1)

    def show_message(self, message, message_type="info", duration=3000):
        # Update colors and icon
        self.toast.configure(fg_color=self.colors.get(message_type, self.colors["info"]))
        self.icon_label.configure(text=self.icons.get(message_type, ""))
        self.message_label.configure(text=message)
        
        # Animate in
        self.animate_in()
        
        # Schedule animate out
        self.after(duration, self.animate_out)

    def animate_in(self):
        def move_step():
            current_y = float(self.place_info()["rely"])
            if current_y < 0.05:
                new_y = min(0.05, current_y + 0.05)
                self.place(rely=new_y)
                self.after(16, move_step)
        move_step()

    def animate_out(self):
        def move_step():
            current_y = float(self.place_info()["rely"])
            if current_y > -0.2:
                new_y = max(-0.2, current_y - 0.05)
                self.place(rely=new_y)
                self.after(16, move_step)
            else:
                self.destroy()
        move_step()

class NetworkSelector(ctk.CTkFrame):
    def __init__(self, parent, **kwargs):
        super().__init__(parent, fg_color="transparent", **kwargs)
        
        # Network name
        self.network_name = ctk.CTkLabel(
            self,
            text="Select Network",
            font=("SF Pro Display", 24, "bold")
        )
        self.network_name.pack(pady=(0, 20))
        
        # Network dropdown with modern styling
        self.network_var = StringVar()
        self.network_menu = ctk.CTkOptionMenu(
            self,
            variable=self.network_var,
            values=["Scanning networks..."],
            width=300,
            height=40,
            font=("SF Pro Display", 14),
            dropdown_font=("SF Pro Display", 14),
            fg_color=("#ffffff", "#2C2C2E"),
            button_color=("#E5E5E7", "#3A3A3C"),
            button_hover_color=("#D1D1D6", "#48484A")
        )
        self.network_menu.pack(pady=(0, 20))
        
        # Password field container
        self.password_frame = ctk.CTkFrame(self, fg_color="transparent")
        self.password_frame.pack(fill="x", padx=20)
        
        # Password field
        self.password_var = StringVar()
        self.password_entry = ctk.CTkEntry(
            self.password_frame,
            textvariable=self.password_var,
            placeholder_text="Enter Password",
            width=300,
            height=40,
            font=("SF Pro Display", 14),
            show="•"
        )
        self.password_entry.pack(pady=(0, 20))
        
        # Password controls
        self.controls_frame = ctk.CTkFrame(self, fg_color="transparent")
        self.controls_frame.pack(fill="x", padx=20)
        
        # Show/Hide password
        self.show_password = ctk.CTkButton(
            self.controls_frame,
            text="👁",
            width=40,
            height=40,
            font=("SF Pro Display", 14),
            fg_color=("#E5E5E7", "#3A3A3C"),
            hover_color=("#D1D1D6", "#48484A"),
            command=self.toggle_password
        )
        self.show_password.pack(side="left", padx=5)
        
        # Clear password
        self.clear_password = ctk.CTkButton(
            self.controls_frame,
            text="⌫",
            width=40,
            height=40,
            font=("SF Pro Display", 14),
            fg_color=("#E5E5E7", "#3A3A3C"),
            hover_color=("#D1D1D6", "#48484A"),
            command=lambda: self.password_var.set("")
        )
        self.clear_password.pack(side="left", padx=5)
        
        # Connect button
        self.connect_button = ctk.CTkButton(
            self,
            text="Connect",
            width=300,
            height=40,
            font=("SF Pro Display", 14, "bold"),
            fg_color="#34C759",
            hover_color="#2FB344",
            command=self.connect
        )
        self.connect_button.pack(pady=20)

    def toggle_password(self):
        current_show = self.password_entry.cget("show")
        self.password_entry.configure(show="" if current_show == "•" else "•")

    def connect(self):
        # This will be implemented in the main app
        pass

class CustomKeyboard(ctk.CTkFrame):
    def __init__(self, master, password_var, on_connect, **kwargs):
        super().__init__(master, **kwargs)
        self.password_var = password_var
        self.on_connect = on_connect
        self.shift_mode = False
        
        # Modern keyboard layouts
        self.normal_layout = [
            ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
            ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'],
            ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'],
            ['⇧', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '⌫'],
            ['123', 'space', '✓']
        ]
        
        self.shift_layout = [
            ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')'],
            ['Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
            ['A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L'],
            ['⇧', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '⌫'],
            ['123', 'space', '✓']
        ]
        
        self.special_layout = [
            ['~', '`', '"', "'", '+', '-', '_', '=', '\\', '|'],
            ['{', '}', '[', ']', '<', '>', ':', ';', '/', '?'],
            ['!', '@', '#', '$', '%', '^', '&', '*'],
            ['abc', '(', ')', ',', '.', '€', '£', '⌫'],
            ['abc', 'space', '✓']
        ]
        
        self.current_layout = self.normal_layout
        self.create_keyboard()

    def create_keyboard(self):
        for widget in self.winfo_children():
            widget.destroy()
            
        self.grid_columnconfigure(tuple(range(10)), weight=1)
        
        for row_idx, row in enumerate(self.current_layout):
            for col_idx, key in enumerate(row):
                # Modern button styling
                btn_width = 60
                btn_height = 45
                corner_radius = 6
                col_span = 1
                
                if key.lower() == 'space':
                    btn_width = 320
                    col_span = 6
                    display_text = ' '
                elif key in ['123', 'abc']:
                    btn_width = 80
                    col_span = 2
                    display_text = key.upper()
                elif key == '✓':
                    btn_width = 80
                    col_span = 2
                    display_text = key
                    fg_color = "#34C759"
                    hover_color = "#2FB344"
                else:
                    display_text = key
                    fg_color = ("#E5E5E7", "#3A3A3C")
                    hover_color = ("#D1D1D6", "#48484A")
                
                button = ctk.CTkButton(
                    self,
                    text=display_text,
                    width=btn_width,
                    height=btn_height,
                    corner_radius=corner_radius,
                    font=("SF Pro Display", 16),
                    fg_color=fg_color if key != '✓' else "#34C759",
                    hover_color=hover_color if key != '✓' else "#2FB344",
                    command=lambda k=key: self.key_press(k)
                )
                
                if row_idx == 2:
                    button.grid(row=row_idx, column=col_idx + 1, columnspan=col_span, padx=2, pady=2)
                else:
                    button.grid(row=row_idx, column=col_idx, columnspan=col_span, padx=2, pady=2)

    def key_press(self, key):
        current_text = self.password_var.get()
        
        if key == '⌫':
            self.password_var.set(current_text[:-1])
        elif key.lower() == 'space':
            self.password_var.set(current_text + ' ')
        elif key == '⇧':
            self.shift_mode = not self.shift_mode
            self.current_layout = self.shift_layout if self.shift_mode else self.normal_layout
            self.create_keyboard()
        elif key in ['123']:
            self.current_layout = self.special_layout
            self.create_keyboard()
        elif key == 'abc':
            self.current_layout = self.normal_layout
            self.create_keyboard()
        elif key == '✓':
            self.on_connect()
        else:
            self.password_var.set(current_text + key)

class WifiConfiguratorApp(ctk.CTk):
    def __init__(self):
        super().__init__()
        self.title("Wi-Fi Configurator")
        self.geometry("1024x600")
        self.resizable(False, False)
        
        # Create main container
        self.main_container = ctk.CTkFrame(self)
        self.main_container.pack(fill="both", expand=True)
        
        # Add network selector
        self.network_selector = NetworkSelector(self.main_container)
        self.network_selector.pack(pady=20)
        
        # Add keyboard
        self.keyboard = CustomKeyboard(
            self.main_container,
            self.network_selector.password_var,
            self.connect_to_wifi,
            fg_color="transparent"
        )
        self.keyboard.pack(fill="both", expand=True, padx=20, pady=20)
        
        # Initialize network scanning
        self.scan_wifi_networks()

    def show_toast(self, message, message_type="info"):
        toast = ToastNotification(self)
        toast.show_message(message, message_type)

    def scan_wifi_networks(self):
        self.show_toast("Scanning for networks...", "info")
        threading.Thread(target=self._scan_networks, daemon=True).start()

    def _scan_networks(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.after(0, lambda: self._update_networks(networks))
                self.after(0, lambda: self.show_toast(
                    f"Found {len(networks)} networks", "success"))
            else:
                self.after(0, lambda: self.show_toast(
                    "Failed to scan networks", "error"))
        except Exception as e:
            self.after(0, lambda: self.show_toast(str(e), "error"))

    def _update_networks(self, networks):
        self.network_selector.network_menu.configure(values=networks)
        if networks:
            self.network_selector.network_var.set(networks[0])

    def connect_to_wifi(self):
        ssid = self.network_selector.network_var.get()
        password = self.network_selector.password_var.get()

        if not ssid:
            self.show_toast("Please select a network", "warning")
            return

        self.show_toast(f"Connecting to {ssid}...", "info")
        threading.Thread(target=self._connect_wifi, args=(ssid, password), daemon=True).start()

    def _connect_wifi(self, ssid, password):
        try:
            result = subprocess.run(
                ["nmcli", "dev", "wifi", "connect", ssid, "password", password],
                capture_output=True, text=True
            )
            
            if result.returncode == 0:
                self.after(0, lambda: self.show_toast(
Editor is loading...
Leave a Comment