Compare commits
	
		
			9 Commits
		
	
	
		
			2.06.2425
			...
			04-06-2025
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fa0fb7ae31 | |||
| c509fdbd18 | |||
| fd957d9742 | |||
| 4e1c3a8e9c | |||
| 7b8ec10e6c | |||
| 47aa3ac749 | |||
| ddae246d46 | |||
| c8d439d428 | |||
| 2463d63c12 | 
							
								
								
									
										26
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								Changelog
									
									
									
									
									
								
							| @@ -6,9 +6,33 @@ My standard System: Linux Mint 22 Cinnamon | |||||||
|  - os import in common_tools.py replaced by other methods |  - os import in common_tools.py replaced by other methods | ||||||
|  - If Wire-Py already runs, prevent further start |  - If Wire-Py already runs, prevent further start | ||||||
|  - for loops with lists replaced by List Comprehensions |  - for loops with lists replaced by List Comprehensions | ||||||
|  - Tunnel in tk.canvas for modern look |  | ||||||
|  - Replace Download Button with Lx Tools installer |  - Replace Download Button with Lx Tools installer | ||||||
|  |  | ||||||
|  |    ### Added | ||||||
|  | 02-07-2025 | ||||||
|  |  | ||||||
|  | - Complete code for faulty f" string configuration dur addicted and fixed | ||||||
|  |  | ||||||
|  | - updater replace Downloadbutton with Lx Tools installer | ||||||
|  |  | ||||||
|  | - remove logviewer icon  | ||||||
|  |  | ||||||
|  | - add settings.png icon for update button | ||||||
|  |  | ||||||
|  |  | ||||||
|  |    ### Added | ||||||
|  | 27-06-2025 | ||||||
|  |    | ||||||
|  |  - Header added for more modern desing | ||||||
|  |  | ||||||
|  |  - Sizes adjust the frames and labels improve | ||||||
|  |  | ||||||
|  |  - More modern desing for listbox, Address, Dns and Endpoint | ||||||
|  |  | ||||||
|  |  - ui works now better with rename button | ||||||
|  |  | ||||||
|  |  - add Image class for manage Images | ||||||
|  |  | ||||||
|    ### Added |    ### Added | ||||||
| 23-06-2025 | 23-06-2025 | ||||||
|  |  | ||||||
|   | |||||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								lx-icons/16/settings.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								lx-icons/16/settings.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 757 B | 
							
								
								
									
										
											BIN
										
									
								
								lx-icons/16/wg_vpn.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								lx-icons/16/wg_vpn.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 846 B | 
							
								
								
									
										419
									
								
								wirepy.py
									
									
									
									
									
								
							
							
						
						
									
										419
									
								
								wirepy.py
									
									
									
									
									
								
							| @@ -6,6 +6,8 @@ import logging | |||||||
| import getpass | import getpass | ||||||
| import shutil | import shutil | ||||||
| import sys | import sys | ||||||
|  | import os | ||||||
|  | import subprocess | ||||||
| import tkinter as tk | import tkinter as tk | ||||||
| import webbrowser | import webbrowser | ||||||
| from functools import partial | from functools import partial | ||||||
| @@ -24,7 +26,7 @@ from shared_libs.common_tools import ( | |||||||
|     Tooltip, |     Tooltip, | ||||||
| ) | ) | ||||||
|  |  | ||||||
| from shared_libs.wp_app_config import AppConfig, Msg | from shared_libs.wp_app_config import AppConfig, Image, Msg | ||||||
|  |  | ||||||
|  |  | ||||||
| class Wirepy(tk.Tk): | class Wirepy(tk.Tk): | ||||||
| @@ -39,6 +41,7 @@ class Wirepy(tk.Tk): | |||||||
|         self.withdraw() |         self.withdraw() | ||||||
|  |  | ||||||
|         self.my_tool_tip = None |         self.my_tool_tip = None | ||||||
|  |  | ||||||
|         self.x_width = AppConfig.UI_CONFIG["window_size"][0] |         self.x_width = AppConfig.UI_CONFIG["window_size"][0] | ||||||
|         self.y_height = AppConfig.UI_CONFIG["window_size"][1] |         self.y_height = AppConfig.UI_CONFIG["window_size"][1] | ||||||
|  |  | ||||||
| @@ -48,23 +51,29 @@ class Wirepy(tk.Tk): | |||||||
|             AppConfig.UI_CONFIG["resizable_window"][0], |             AppConfig.UI_CONFIG["resizable_window"][0], | ||||||
|             AppConfig.UI_CONFIG["resizable_window"][1], |             AppConfig.UI_CONFIG["resizable_window"][1], | ||||||
|         ) |         ) | ||||||
|  |         self.minsize( | ||||||
|  |             AppConfig.UI_CONFIG["window_size"][0], | ||||||
|  |             AppConfig.UI_CONFIG["window_size"][1], | ||||||
|  |         ) | ||||||
|         self.title(AppConfig.UI_CONFIG["window_title"]) |         self.title(AppConfig.UI_CONFIG["window_title"]) | ||||||
|  |         self.image_manager = Image() | ||||||
|         self.columnconfigure(0, weight=1) |  | ||||||
|         self.rowconfigure(0, weight=1) |  | ||||||
|         self.tk.call("source", f"{AppConfig.SYSTEM_PATHS['tcl_path']}/water.tcl") |         self.tk.call("source", f"{AppConfig.SYSTEM_PATHS['tcl_path']}/water.tcl") | ||||||
|         ConfigManager.init(AppConfig.SETTINGS_FILE) |         ConfigManager.init(AppConfig.SETTINGS_FILE) | ||||||
|         theme = ConfigManager.get("theme") |         theme = ConfigManager.get("theme") | ||||||
|         ThemeManager.change_theme(self, theme) |         ThemeManager.change_theme(self, theme) | ||||||
|  |  | ||||||
|         # Load the image file from the disk |         # Try to set icon | ||||||
|         self.wg_icon = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"]) |         try: | ||||||
|  |             icon = self.image_manager.load_image("icon_vpn") | ||||||
|         # Set it as the window icon |             if icon: | ||||||
|         self.iconphoto(True, self.wg_icon) |                 self.iconphoto(True, icon) | ||||||
|  |         except: | ||||||
|  |             pass | ||||||
|  |  | ||||||
|         # Add the widgets |         # Add the widgets | ||||||
|         FrameWidgets(self).grid() |         FrameWidgets(self).grid() | ||||||
|  |         self.columnconfigure(0, weight=1) | ||||||
|  |         self.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|         # Center the window on the primary monitor |         # Center the window on the primary monitor | ||||||
|         LxTools.center_window_cross_platform(self, self.x_width, self.y_height) |         LxTools.center_window_cross_platform(self, self.x_width, self.y_height) | ||||||
| @@ -87,13 +96,14 @@ class FrameWidgets(ttk.Frame): | |||||||
|         self.dns = None |         self.dns = None | ||||||
|         self.address = None |         self.address = None | ||||||
|         self.auto_con = None |         self.auto_con = None | ||||||
|         self.style = ttk.Style() |         self.image_manager = Image() | ||||||
|         self.wg_vpn_start = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_start"]) |         self.columnconfigure(0, weight=1) | ||||||
|         self.wg_vpn_stop = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_stop"]) |         self.rowconfigure(0, weight=1) | ||||||
|         self.imp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_import"]) |         self.columnconfigure(1, weight=1) | ||||||
|         self.tr_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_trash"]) |         self.rowconfigure(1, weight=1) | ||||||
|         self.exp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_export"]) |         self.columnconfigure(2, weight=18) | ||||||
|         self.warning_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_error"]) |         self.rowconfigure(2, weight=1) | ||||||
|  |         self.rowconfigure(3, weight=1) | ||||||
|  |  | ||||||
|         # StringVar-Variables initialization |         # StringVar-Variables initialization | ||||||
|         self.tooltip_state = tk.BooleanVar() |         self.tooltip_state = tk.BooleanVar() | ||||||
| @@ -122,20 +132,10 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         # Frame for Menu |         # Frame for Menu | ||||||
|         self.menu_frame = ttk.Frame(self) |         self.menu_frame = ttk.Frame(self) | ||||||
|         self.menu_frame.configure(relief="flat") |         self.menu_frame.grid(column=0, columnspan=3, row=1, sticky="we") | ||||||
|         self.menu_frame.grid(column=0, row=0, columnspan=4, sticky="w") |  | ||||||
|  |  | ||||||
|         # App Menu |  | ||||||
|         self.version_lb = ttk.Label(self.menu_frame, text=AppConfig.VERSION) |  | ||||||
|         self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff") |  | ||||||
|         self.version_lb.grid(column=0, row=0, rowspan=4, padx=10) |  | ||||||
|  |  | ||||||
|         Tooltip( |  | ||||||
|             self.version_lb, f"Version: {AppConfig.VERSION[2:]}", self.tooltip_state |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         self.options_btn = ttk.Menubutton(self.menu_frame, text=_("Options")) |         self.options_btn = ttk.Menubutton(self.menu_frame, text=_("Options")) | ||||||
|         self.options_btn.grid(column=1, columnspan=1, row=0) |         self.options_btn.grid(column=0, row=0) | ||||||
|  |  | ||||||
|         Tooltip(self.options_btn, Msg.TTIP["settings"], self.tooltip_state) |         Tooltip(self.options_btn, Msg.TTIP["settings"], self.tooltip_state) | ||||||
|  |  | ||||||
| @@ -147,9 +147,8 @@ class FrameWidgets(ttk.Frame): | |||||||
|             command=lambda: self.update_setting(self.set_update.get()), |             command=lambda: self.update_setting(self.set_update.get()), | ||||||
|             variable=self.set_update, |             variable=self.set_update, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         self.updates_lb = ttk.Label(self.menu_frame, textvariable=self.update_label) |         self.updates_lb = ttk.Label(self.menu_frame, textvariable=self.update_label) | ||||||
|         self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10) |         self.updates_lb.grid(column=2, row=0) | ||||||
|         self.updates_lb.grid_remove() |         self.updates_lb.grid_remove() | ||||||
|         self.update_label.trace_add("write", self.update_label_display) |         self.update_label.trace_add("write", self.update_label_display) | ||||||
|         self.update_foreground.trace_add("write", self.update_label_display) |         self.update_foreground.trace_add("write", self.update_label_display) | ||||||
| @@ -177,69 +176,148 @@ class FrameWidgets(ttk.Frame): | |||||||
|         self.about_btn = ttk.Button( |         self.about_btn = ttk.Button( | ||||||
|             self.menu_frame, text=_("About"), style="Toolbutton", command=self.about |             self.menu_frame, text=_("About"), style="Toolbutton", command=self.about | ||||||
|         ) |         ) | ||||||
|         self.about_btn.grid(column=2, columnspan=2, row=0) |         self.about_btn.grid(column=1, row=0) | ||||||
|         self.readme = tk.Menu(self) |  | ||||||
|  |  | ||||||
|         self.a = Tunnel.get_active() |         self.a = Tunnel.get_active() | ||||||
|  |  | ||||||
|         # Label Frame 1 |         # Header Frame | ||||||
|         self.lb_frame_btn_lbox = ttk.Frame(self) |         # Festlegen der Farbe | ||||||
|         self.lb_frame_btn_lbox.configure(relief="flat") |         self.header_frame = tk.Frame(self, bg="#2c3e50") | ||||||
|         self.lb_frame_btn_lbox.grid(column=0, rowspan=3, row=1) |         self.wg_icon_header_frame = tk.Frame(self.header_frame, bg="#2c3e50") | ||||||
|  |         self.header_label = tk.Label( | ||||||
|         # Label Frame 2 |             self.header_frame, | ||||||
|         self.lb_frame = ttk.Frame(self) |             text=_("Lx Tools Wire-Py"), | ||||||
|         self.lb_frame.configure(relief="solid") |             font=("Helvetica", 12, "bold"), | ||||||
|         self.lb_frame.grid(column=2, row=2, sticky="snew", padx=20, pady=5) |             fg="#ffffff", | ||||||
|  |             bg="#2c3e50", | ||||||
|         # Label Frame 3 |  | ||||||
|         self.lb_frame2 = ttk.Frame(self) |  | ||||||
|         self.lb_frame2.configure(relief="solid") |  | ||||||
|         self.lb_frame2.grid(column=2, row=3, sticky="snew", padx=20, pady=5) |  | ||||||
|  |  | ||||||
|         # Bottom Frame 4 |  | ||||||
|         self.lb_frame3 = ttk.Frame(self) |  | ||||||
|         self.lb_frame3.configure(relief="flat") |  | ||||||
|         self.lb_frame3.grid( |  | ||||||
|             column=0, row=5, columnspan=4, sticky="snew", padx=2, pady=2 |  | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         # Bottom Frame 5 |         self.version_label = tk.Label( | ||||||
|         self.lb_frame4 = ttk.Frame(self) |             self.header_frame, | ||||||
|         self.lb_frame4.configure(relief="flat") |             text=f"{AppConfig.VERSION} • {Msg.STR['header_left_bottom']}", | ||||||
|         self.lb_frame4.grid(column=2, row=5, columnspan=3, sticky="e", padx=15) |             font=("Helvetica", 9), | ||||||
|  |             fg="#bdc3c7", | ||||||
|  |             bg="#2c3e50", | ||||||
|  |         ) | ||||||
|  |         self.info_label = tk.Label( | ||||||
|  |             self.header_frame, | ||||||
|  |             text=Msg.STR["header_right_top"], | ||||||
|  |             font=("Helvetica", 10), | ||||||
|  |             fg="#ecf0f1", | ||||||
|  |             bg="#2c3e50", | ||||||
|  |         ) | ||||||
|  |         self.header_frame.grid(column=0, columnspan=3, row=0, sticky="nsew") | ||||||
|  |         self.wg_icon_header_frame.grid(column=0, row=0, rowspan=2, sticky="w") | ||||||
|  |  | ||||||
|  |         self.wg_icon_header_label = tk.Label( | ||||||
|  |             self.wg_icon_header_frame, | ||||||
|  |             image=self.image_manager.load_image("icon_header"), | ||||||
|  |             bg="#2c3e50", | ||||||
|  |         ) | ||||||
|  |         self.wg_icon_header_label.grid(column=0, row=0, sticky="e", ipadx=10) | ||||||
|  |  | ||||||
|  |         self.header_label.grid( | ||||||
|  |             column=1, | ||||||
|  |             row=0, | ||||||
|  |             sticky="w", | ||||||
|  |             padx=(5, 20), | ||||||
|  |             pady=(15, 5), | ||||||
|  |             ipady=4, | ||||||
|  |         ) | ||||||
|  |         self.version_label.grid(column=1, row=1, sticky="w", padx=(5, 20), pady=(0, 10)) | ||||||
|  |         self.info_label.grid(column=2, row=0, sticky="ne", padx=(10, 10), pady=(10, 0)) | ||||||
|  |         self.header_frame.columnconfigure(1, weight=1, pad=2) | ||||||
|  |         self.header_frame.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|  |         # Frame for Control Buttons (Start, Stop, Import, Trash, Export) | ||||||
|  |         self.control_buttons_frame = ttk.Frame(self) | ||||||
|  |         self.control_buttons_frame.grid(column=0, row=2, sticky="w", padx=(15, 0)) | ||||||
|  |         self.control_buttons_frame.columnconfigure(0, weight=1) | ||||||
|  |         self.control_buttons_frame.rowconfigure(2, weight=1) | ||||||
|  |  | ||||||
|  |         # Frame for Listbox and Scrollbar | ||||||
|  |         self.list_container_frame = ttk.Frame(self) | ||||||
|  |         self.list_container_frame.grid(column=1, row=2, sticky="nsew") | ||||||
|  |         self.list_container_frame.columnconfigure(1, weight=1) | ||||||
|  |         self.list_container_frame.rowconfigure(2, weight=1) | ||||||
|  |         self.list_frame = ttk.LabelFrame(self.list_container_frame, text=_("Tunnels")) | ||||||
|  |         self.list_frame.grid(column=0, row=0, sticky="nsew", padx=10, ipady=20) | ||||||
|  |         # Listbox with Scrollbar | ||||||
|  |         self.list_box = tk.Listbox(self.list_frame, selectmode="single") | ||||||
|  |         self.list_box.config( | ||||||
|  |             relief="flat", | ||||||
|  |             font=("Ubuntu", 12, "bold"), | ||||||
|  |         ) | ||||||
|  |         self.list_box.grid(column=0, row=0, sticky="nsew") | ||||||
|  |         self.list_box.event_add("<<ClickEvent>>", "<Button-1>") | ||||||
|  |         self.list_box.bind("<<ClickEvent>>", self.enable_check_box) | ||||||
|  |         self.scrollbar = ttk.Scrollbar( | ||||||
|  |             self.list_frame, orient="vertical", command=self.list_box.yview | ||||||
|  |         ) | ||||||
|  |         self.scrollbar.grid(column=1, row=0, sticky="ns") | ||||||
|  |         self.list_box.configure(yscrollcommand=self.scrollbar.set) | ||||||
|  |         self.scrollbar.columnconfigure(1, weight=1) | ||||||
|  |         self.scrollbar.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|  |         # Frame for Active Tunnel, Interface and Peer | ||||||
|  |         # Right Side Frame | ||||||
|  |         self.right_side_frame = ttk.Frame(self) | ||||||
|  |         self.right_side_frame.grid(column=2, row=2, sticky="nsew") | ||||||
|  |         self.right_side_frame.columnconfigure(2, weight=1) | ||||||
|  |         self.right_side_frame.rowconfigure(2, weight=1) | ||||||
|  |  | ||||||
|         # Show active Label |         # Show active Label | ||||||
|         self.select_tunnel = None |         self.select_tunnel = None | ||||||
|         self.lb = ttk.Label(self, text=_("Active: ")) |         self.active_frame = ttk.LabelFrame( | ||||||
|         self.lb.config(font=("Ubuntu", 11, "bold")) |             self.right_side_frame, text=_("Active Tunnel") | ||||||
|         self.lb.grid(column=2, row=1, padx=15, pady=4, sticky="w") |         ) | ||||||
|  |  | ||||||
|  |         self.active_frame.grid( | ||||||
|  |             column=0, row=0, sticky="nsew", padx=10, pady=5, columnspan=3 | ||||||
|  |         ) | ||||||
|  |         self.active_frame.columnconfigure(0, weight=1) | ||||||
|  |         self.active_frame.rowconfigure(0, weight=1) | ||||||
|  |         # Interface Label Frame | ||||||
|  |         self.interface_frame = ttk.LabelFrame( | ||||||
|  |             self.right_side_frame, text=_("Interface") | ||||||
|  |         ) | ||||||
|  |         self.interface_frame.grid( | ||||||
|  |             column=0, row=1, sticky="nsew", padx=10, pady=5, columnspan=3 | ||||||
|  |         ) | ||||||
|  |         self.interface_frame.columnconfigure(0, weight=1) | ||||||
|  |         self.interface_frame.rowconfigure(1, weight=1) | ||||||
|  |  | ||||||
|  |         # Peer Label Frame | ||||||
|  |         self.peer_frame = ttk.LabelFrame(self.right_side_frame, text=_("Peer")) | ||||||
|  |         self.peer_frame.grid( | ||||||
|  |             column=0, row=2, sticky="nsew", padx=10, pady=5, columnspan=3 | ||||||
|  |         ) | ||||||
|  |         self.peer_frame.columnconfigure(0, weight=1) | ||||||
|  |         self.peer_frame.rowconfigure(2, weight=1) | ||||||
|  |  | ||||||
|  |         # Auto Start Label Frame | ||||||
|  |         self.autoconnect_frame = ttk.Frame(self) | ||||||
|  |         self.autoconnect_frame.grid(column=0, row=3, columnspan=2, sticky="w") | ||||||
|  |  | ||||||
|  |         # Rename Frame | ||||||
|  |         self.rename_frame = ttk.Frame(self) | ||||||
|  |         self.rename_frame.grid(column=2, padx=10, row=3, sticky="nsew") | ||||||
|  |         self.rename_frame.columnconfigure(0, weight=2) | ||||||
|  |         self.rename_frame.columnconfigure(1, weight=1) | ||||||
|  |  | ||||||
|         # Label to Show active Tunnel |         # Label to Show active Tunnel | ||||||
|         self.str_var = tk.StringVar(value=self.a) |         self.str_var = tk.StringVar(value=self.a) | ||||||
|         self.color_label() |         self.color_label() | ||||||
|  |  | ||||||
|         # Interface Label |         # Interface Label | ||||||
|         self.interface = ttk.Label(self.lb_frame, text=_("Interface")) |         self.interface = ttk.Label(self.interface_frame) | ||||||
|         self.interface.grid(column=0, row=3, sticky="we", padx=120) |         self.interface.grid(column=0, row=4, sticky="we") | ||||||
|         self.interface.config(font=("Ubuntu", 9)) |         self.interface.config(font=("Ubuntu", 9)) | ||||||
|  |  | ||||||
|         # Peer Label |         # Peer Label | ||||||
|         self.peer = ttk.Label(self.lb_frame2, text=_("Peer")) |         self.peer = ttk.Label(self.peer_frame) | ||||||
|         self.peer.config(font=("Ubuntu", 9)) |         self.peer.config(font=("Ubuntu", 9)) | ||||||
|         self.peer.grid(column=0, row=4, sticky="we", padx=130) |         self.peer.grid(column=0, row=5, sticky="we") | ||||||
|  |  | ||||||
|         # Listbox with Scrollbar |  | ||||||
|         self.l_box = tk.Listbox(self.lb_frame_btn_lbox, selectmode="single") |  | ||||||
|         self.l_box.config(relief="ridge", font=("Ubuntu", 12, "bold")) |  | ||||||
|         self.l_box.grid(column=1, rowspan=4, row=0, sticky="ns") |  | ||||||
|         self.l_box.event_add("<<ClickEvent>>", "<Button-1>") |  | ||||||
|         self.l_box.bind("<<ClickEvent>>", self.enable_check_box) |  | ||||||
|         self.scrollbar = ttk.Scrollbar( |  | ||||||
|             self.lb_frame_btn_lbox, orient="vertical", command=self.l_box.yview |  | ||||||
|         ) |  | ||||||
|         self.scrollbar.grid(column=1, rowspan=4, row=0, sticky="nse") |  | ||||||
|         self.l_box.configure(yscrollcommand=self.scrollbar.set) |  | ||||||
|  |  | ||||||
|         # Tunnel List |         # Tunnel List | ||||||
|         self.tl = Tunnel.parse_files_to_dictionary(directory=AppConfig.TEMP_DIR) |         self.tl = Tunnel.parse_files_to_dictionary(directory=AppConfig.TEMP_DIR) | ||||||
| @@ -247,8 +325,8 @@ class FrameWidgets(ttk.Frame): | |||||||
|         AppConfig.ensure_directories() |         AppConfig.ensure_directories() | ||||||
|  |  | ||||||
|         for tunnels, values in self.tl.items(): |         for tunnels, values in self.tl.items(): | ||||||
|             self.l_box.insert("end", tunnels) |             self.list_box.insert("end", tunnels) | ||||||
|             self.l_box.update() |             self.list_box.update() | ||||||
|  |  | ||||||
|         # Button Vpn |         # Button Vpn | ||||||
|         if self.a != "": |         if self.a != "": | ||||||
| @@ -267,52 +345,55 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         # Button Import |         # Button Import | ||||||
|         self.btn_i = ttk.Button( |         self.btn_i = ttk.Button( | ||||||
|             self.lb_frame_btn_lbox, |             self.control_buttons_frame, | ||||||
|             image=self.imp_pic, |             image=self.image_manager.load_image("icon_import"), | ||||||
|             command=self.import_sl, |             command=self.import_sl, | ||||||
|             padding=0, |             padding=0, | ||||||
|         ) |         ) | ||||||
|         self.btn_i.grid(column=0, row=1, padx=15, pady=8) |         self.btn_i.grid(column=0, row=1, pady=8) | ||||||
|  |  | ||||||
|         Tooltip(self.btn_i, Msg.TTIP["import_tl"], self.tooltip_state) |         Tooltip(self.btn_i, Msg.TTIP["import_tl"], self.tooltip_state) | ||||||
|  |  | ||||||
|         # Button Trash |         # Button Trash | ||||||
|         self.btn_tr = ttk.Button( |         self.btn_tr = ttk.Button( | ||||||
|             self.lb_frame_btn_lbox, |             self.control_buttons_frame, | ||||||
|             image=self.tr_pic, |             image=self.image_manager.load_image("icon_trash"), | ||||||
|             command=self.delete, |             command=self.delete, | ||||||
|             padding=0, |             padding=0, | ||||||
|             style="CButton.TButton", |  | ||||||
|         ) |         ) | ||||||
|         self.btn_tr.grid(column=0, row=2, padx=15, pady=8) |         self.btn_tr.grid(column=0, row=2, pady=8) | ||||||
|  |  | ||||||
|         if self.l_box.size() == 0: |         if self.list_box.size() == 0: | ||||||
|             Tooltip(self.btn_tr, Msg.TTIP["trash_tl_info"], self.tooltip_state) |             Tooltip(self.btn_tr, Msg.TTIP["trash_tl_info"], self.tooltip_state) | ||||||
|         else: |         else: | ||||||
|             Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state) |             Tooltip(self.btn_tr, Msg.TTIP["trash_tl"], self.tooltip_state) | ||||||
|  |  | ||||||
|         # Button Export |         # Button Export | ||||||
|         self.btn_exp = ttk.Button( |         self.btn_exp = ttk.Button( | ||||||
|             self.lb_frame_btn_lbox, |             self.control_buttons_frame, | ||||||
|             image=self.exp_pic, |             image=self.image_manager.load_image("icon_export"), | ||||||
|             command=lambda: Tunnel.export(), |             command=lambda: Tunnel.export(), | ||||||
|             padding=0, |             padding=0, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         self.btn_exp.grid(column=0, row=3, padx=15, pady=8) |         self.btn_exp.grid(column=0, row=3, pady=8) | ||||||
|  |         self.btn_exp.columnconfigure(0, weight=1) | ||||||
|  |         self.btn_exp.rowconfigure(3, weight=1) | ||||||
|  |  | ||||||
|         if self.l_box.size() == 0: |         if self.list_box.size() == 0: | ||||||
|             Tooltip(self.btn_exp, Msg.TTIP["export_tl_info"], self.tooltip_state) |             Tooltip(self.btn_exp, Msg.TTIP["export_tl_info"], self.tooltip_state) | ||||||
|         else: |         else: | ||||||
|             Tooltip(self.btn_exp, Msg.TTIP["export_tl"], self.tooltip_state) |             Tooltip(self.btn_exp, Msg.TTIP["export_tl"], self.tooltip_state) | ||||||
|  |  | ||||||
|         # Label Entry |         # Label Entry | ||||||
|         self.lb_rename = ttk.Entry(self.lb_frame4, width=20) |         self.lb_rename = ttk.Entry(self.rename_frame) | ||||||
|         self.lb_rename.grid(column=2, row=0, padx=8, pady=10, sticky="ne") |         self.lb_rename.grid(column=0, row=0, padx=8, pady=10, sticky="ne") | ||||||
|  |         self.lb_rename.config(width=15) | ||||||
|  |  | ||||||
|         self.lb_rename.insert(0, _("Max. 12 characters!")) |         self.lb_rename.insert(0, _("Max. 12 characters!")) | ||||||
|         self.lb_rename.config(state="disable") |         self.lb_rename.config(state="disable") | ||||||
|  |  | ||||||
|         if self.l_box.size() != 0: |         if self.list_box.size() != 0: | ||||||
|             Tooltip( |             Tooltip( | ||||||
|                 self.lb_rename, |                 self.lb_rename, | ||||||
|                 Msg.TTIP["rename_tl"], |                 Msg.TTIP["rename_tl"], | ||||||
| @@ -331,14 +412,13 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         # Button Rename |         # Button Rename | ||||||
|         self.btn_rename = ttk.Button( |         self.btn_rename = ttk.Button( | ||||||
|             self.lb_frame4, |             self.rename_frame, | ||||||
|             text=_("Rename"), |             text=_("Rename"), | ||||||
|             state="disable", |             state="disable", | ||||||
|             command=self.tl_rename, |             command=self.tl_rename, | ||||||
|             padding=4, |             width=15, | ||||||
|             style="RnButton.TButton", |  | ||||||
|         ) |         ) | ||||||
|         self.btn_rename.grid(column=3, row=0, padx=5, pady=10, sticky="ne") |         self.btn_rename.grid(column=1, row=0, pady=10, sticky="nsew") | ||||||
|  |  | ||||||
|         # Check Buttons |         # Check Buttons | ||||||
|         self.selected_option = tk.IntVar() |         self.selected_option = tk.IntVar() | ||||||
| @@ -347,19 +427,21 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         # Frame for Labels, Entry and Button |         # Frame for Labels, Entry and Button | ||||||
|         self.autoconnect = ttk.Label( |         self.autoconnect = ttk.Label( | ||||||
|             self.lb_frame3, textvariable=self.autoconnect_var, width=15 |             self.autoconnect_frame, textvariable=self.autoconnect_var | ||||||
|         ) |         ) | ||||||
|         self.autoconnect.config(font=("Ubuntu", 11)) |         self.autoconnect.config(font=("Ubuntu", 11)) | ||||||
|         self.autoconnect.grid(column=1, row=0, sticky="e", pady=19) |         self.autoconnect.grid(column=1, row=0, pady=10, sticky="nsew") | ||||||
|  |         self.autoconnect.columnconfigure(1, weight=1) | ||||||
|  |         self.autoconnect.rowconfigure(0, weight=1) | ||||||
|         self.wg_autostart = ttk.Checkbutton( |         self.wg_autostart = ttk.Checkbutton( | ||||||
|             self.lb_frame3, |             self.autoconnect_frame, | ||||||
|             text=_("Autoconnect on:"), |             text=_("Autoconnect on:"), | ||||||
|             variable=self.selected_option, |             variable=self.selected_option, | ||||||
|             command=self.box_set, |             command=self.box_set, | ||||||
|         ) |         ) | ||||||
|         self.wg_autostart.grid(column=0, row=0, pady=15, padx=15, sticky="nw") |         self.wg_autostart.grid(column=0, row=0, pady=10, padx=(10, 0), sticky="ew") | ||||||
|  |  | ||||||
|         if self.l_box.size() >= 1 and len(self.l_box.curselection()) >= 1: |         if self.list_box.size() >= 1 and len(self.list_box.curselection()) >= 1: | ||||||
|             Tooltip( |             Tooltip( | ||||||
|                 self.wg_autostart, |                 self.wg_autostart, | ||||||
|                 Msg.TTIP["autostart"], |                 Msg.TTIP["autostart"], | ||||||
| @@ -368,7 +450,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|                 y_offset=-40, |                 y_offset=-40, | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         if self.l_box.size() == 0: |         if self.list_box.size() == 0: | ||||||
|             Tooltip( |             Tooltip( | ||||||
|                 self.wg_autostart, |                 self.wg_autostart, | ||||||
|                 Msg.TTIP["autostart_info"], |                 Msg.TTIP["autostart_info"], | ||||||
| @@ -401,6 +483,15 @@ class FrameWidgets(ttk.Frame): | |||||||
|         else: |         else: | ||||||
|             self.updates_lb.grid_remove() |             self.updates_lb.grid_remove() | ||||||
|  |  | ||||||
|  |     def updater(self): | ||||||
|  |         """Start the lxtools_installer""" | ||||||
|  |         tmp_dir = Path("/tmp/lxtools") | ||||||
|  |         Path.mkdir(tmp_dir, exist_ok=True) | ||||||
|  |         os.chdir(tmp_dir) | ||||||
|  |         result = subprocess.run(["/usr/local/bin/lxtools_installer"], check=False) | ||||||
|  |         if result.returncode != 0: | ||||||
|  |             MessageDialog("error", result.stderr) | ||||||
|  |  | ||||||
|     # Update the labels based on the result |     # Update the labels based on the result | ||||||
|     def update_ui_for_update(self, res): |     def update_ui_for_update(self, res): | ||||||
|         """Update UI elements based on an update check result""" |         """Update UI elements based on an update check result""" | ||||||
| @@ -437,25 +528,20 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             self.set_update.set(value=0) |             self.set_update.set(value=0) | ||||||
|             update_text = f"Update {res} {_('available!')}" |  | ||||||
|  |  | ||||||
|             # Clear the label text since we'll show the button instead |             # Clear the label text since we'll show the button instead | ||||||
|             self.update_label.set("") |             self.update_label.set("") | ||||||
|  |  | ||||||
|             # Create the update button |             # Create the update button | ||||||
|             self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text) |             self.update_btn = ttk.Button( | ||||||
|             self.update_btn.grid(column=4, columnspan=3, row=0, padx=0) |                 self.menu_frame, | ||||||
|             Tooltip( |                 image=self.image_manager.load_image("update"), | ||||||
|                 self.update_btn, _("Click to download new version"), self.tooltip_state |                 style="Toolbutton", | ||||||
|  |                 command=self.updater, | ||||||
|             ) |             ) | ||||||
|  |             self.update_btn.grid(column=5, row=0, padx=0) | ||||||
|             self.download = tk.Menu(self, relief="flat") |             Tooltip( | ||||||
|             self.update_btn.configure(menu=self.download, style="Toolbutton") |                 self.update_btn, _("Click to install new version"), self.tooltip_state | ||||||
|             self.download.add_command( |  | ||||||
|                 label=_("Download"), |  | ||||||
|                 command=lambda: GiteaUpdate.download( |  | ||||||
|                     f"{AppConfig.DOWNLOAD_URL}/{res}.zip", res |  | ||||||
|                 ), |  | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
| @@ -479,7 +565,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|                 None, |                 None, | ||||||
|                 partial(webbrowser.open, "https://git.ilunix.de/punix/Wire-Py"), |                 partial(webbrowser.open, "https://git.ilunix.de/punix/Wire-Py"), | ||||||
|             ], |             ], | ||||||
|             icon=AppConfig.IMAGE_PATHS["icon_vpn"], |             icon="/usr/share/icons/lx-icons/64/wg_vpn.png", | ||||||
|             wraplength=420, |             wraplength=420, | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
| @@ -562,7 +648,9 @@ class FrameWidgets(ttk.Frame): | |||||||
|         new_theme = "dark" if current_theme == "light" else "light" |         new_theme = "dark" if current_theme == "light" else "light" | ||||||
|         ThemeManager.change_theme(self, new_theme, new_theme) |         ThemeManager.change_theme(self, new_theme, new_theme) | ||||||
|         self.color_label() |         self.color_label() | ||||||
|  |         self.header_label.config(fg="#ffffff") | ||||||
|         self.update_theme_label()  # Update the theme label |         self.update_theme_label()  # Update the theme label | ||||||
|  |  | ||||||
|         # Update Menulfield |         # Update Menulfield | ||||||
|         self.settings.entryconfigure(2, label=self.theme_label.get()) |         self.settings.entryconfigure(2, label=self.theme_label.get()) | ||||||
|  |  | ||||||
| @@ -571,14 +659,16 @@ class FrameWidgets(ttk.Frame): | |||||||
|         Start Button |         Start Button | ||||||
|         """ |         """ | ||||||
|         self.btn_stst = ttk.Button( |         self.btn_stst = ttk.Button( | ||||||
|             self.lb_frame_btn_lbox, |             self.control_buttons_frame, | ||||||
|             image=self.wg_vpn_start, |             image=self.image_manager.load_image("icon_start"), | ||||||
|             command=lambda: self.wg_switch("start"), |             command=lambda: self.wg_switch("start"), | ||||||
|             padding=0, |             padding=0, | ||||||
|         ) |         ) | ||||||
|         self.btn_stst.grid(column=0, row=0, padx=5, pady=8) |         self.btn_stst.grid(column=0, row=0, pady=8) | ||||||
|  |         self.btn_stst.columnconfigure(0, weight=1) | ||||||
|  |         self.btn_stst.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|         if self.l_box.size() == 0: |         if self.list_box.size() == 0: | ||||||
|             Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state) |             Tooltip(self.btn_stst, Msg.TTIP["empty_list"], self.tooltip_state) | ||||||
|         else: |         else: | ||||||
|             Tooltip(self.btn_stst, Msg.TTIP["start_tl"], self.tooltip_state) |             Tooltip(self.btn_stst, Msg.TTIP["start_tl"], self.tooltip_state) | ||||||
| @@ -590,28 +680,32 @@ class FrameWidgets(ttk.Frame): | |||||||
|         if ConfigManager.get("theme") == "light": |         if ConfigManager.get("theme") == "light": | ||||||
|  |  | ||||||
|             self.lb_tunnel = ttk.Label( |             self.lb_tunnel = ttk.Label( | ||||||
|                 self, textvariable=self.str_var, foreground="green" |                 self.active_frame, textvariable=self.str_var, foreground="green" | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             self.lb_tunnel = ttk.Label( |             self.lb_tunnel = ttk.Label( | ||||||
|                 self, textvariable=self.str_var, foreground="yellow" |                 self.active_frame, textvariable=self.str_var, foreground="yellow" | ||||||
|             ) |             ) | ||||||
|  |  | ||||||
|         self.lb_tunnel.config(font=("Ubuntu", 11, "bold")) |         self.lb_tunnel.config(font=("Ubuntu", 11, "bold")) | ||||||
|         self.lb_tunnel.grid(column=2, padx=10, row=1) |         self.lb_tunnel.grid(column=0, row=0, padx=10, pady=(0, 10), sticky="n") | ||||||
|  |         self.lb_tunnel.columnconfigure(0, weight=1) | ||||||
|  |         self.lb_tunnel.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|     def stop(self) -> None: |     def stop(self) -> None: | ||||||
|         """ |         """ | ||||||
|         Stop Button |         Stop Button | ||||||
|         """ |         """ | ||||||
|         self.btn_stst = ttk.Button( |         self.btn_stst = ttk.Button( | ||||||
|             self.lb_frame_btn_lbox, |             self.control_buttons_frame, | ||||||
|             image=self.wg_vpn_stop, |             image=self.image_manager.load_image("icon_stop"), | ||||||
|             command=lambda: self.wg_switch("stop"), |             command=lambda: self.wg_switch("stop"), | ||||||
|             padding=0, |             padding=0, | ||||||
|         ) |         ) | ||||||
|         self.btn_stst.grid(column=0, row=0, padx=5, pady=8) |         self.btn_stst.grid(column=0, row=0, pady=8) | ||||||
|  |         self.btn_stst.columnconfigure(0, weight=1) | ||||||
|  |         self.btn_stst.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|         Tooltip(self.btn_stst, Msg.TTIP["stop_tl"], self.tooltip_state) |         Tooltip(self.btn_stst, Msg.TTIP["stop_tl"], self.tooltip_state) | ||||||
|  |  | ||||||
| @@ -635,11 +729,11 @@ class FrameWidgets(ttk.Frame): | |||||||
|             ) |             ) | ||||||
|             data_import, key_name = Tunnel.parse_files_to_dictionary(filepath=filepath) |             data_import, key_name = Tunnel.parse_files_to_dictionary(filepath=filepath) | ||||||
|  |  | ||||||
|             if CryptoUtil.find_key(f"{data_import[key_name]["PrivateKey"]}="): |             if CryptoUtil.find_key(f"{data_import[key_name]['PrivateKey']}="): | ||||||
|                 MessageDialog("error", Msg.STR["tl_exist"], title=Msg.STR["imp_err"]) |                 MessageDialog("error", Msg.STR["tl_exist"], title=Msg.STR["imp_err"]) | ||||||
|  |  | ||||||
|             elif not CryptoUtil.is_valid_base64( |             elif not CryptoUtil.is_valid_base64( | ||||||
|                 f"{data_import[key_name]["PrivateKey"]}=" |                 f"{data_import[key_name]['PrivateKey']}=" | ||||||
|             ):  # 2. Second check: Is it valid Base64? |             ):  # 2. Second check: Is it valid Base64? | ||||||
|                 MessageDialog( |                 MessageDialog( | ||||||
|                     "error", |                     "error", | ||||||
| @@ -699,11 +793,11 @@ class FrameWidgets(ttk.Frame): | |||||||
|                 AppConfig.ensure_directories() |                 AppConfig.ensure_directories() | ||||||
|                 self.str_var.set("") |                 self.str_var.set("") | ||||||
|                 self.a = Tunnel.get_active() |                 self.a = Tunnel.get_active() | ||||||
|                 self.l_box.insert(0, self.a) |                 self.list_box.insert(0, self.a) | ||||||
|                 self.wg_autostart.configure(state="normal") |                 self.wg_autostart.configure(state="normal") | ||||||
|                 self.l_box.selection_clear(0, tk.END) |                 self.list_box.selection_clear(0, tk.END) | ||||||
|                 self.l_box.update() |                 self.list_box.update() | ||||||
|                 self.l_box.selection_set(0) |                 self.list_box.selection_set(0) | ||||||
|  |  | ||||||
|                 Tooltip( |                 Tooltip( | ||||||
|                     self.wg_autostart, |                     self.wg_autostart, | ||||||
| @@ -748,8 +842,8 @@ class FrameWidgets(ttk.Frame): | |||||||
|         delete Wireguard Tunnel |         delete Wireguard Tunnel | ||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             self.select_tunnel = self.l_box.curselection() |             self.select_tunnel = self.list_box.curselection() | ||||||
|             select_tl = self.l_box.get(self.select_tunnel[0]) |             select_tl = self.list_box.get(self.select_tunnel[0]) | ||||||
|  |  | ||||||
|             process: CompletedProcess[str] = run( |             process: CompletedProcess[str] = run( | ||||||
|                 ["nmcli", "connection", "delete", select_tl], |                 ["nmcli", "connection", "delete", select_tl], | ||||||
| @@ -763,7 +857,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|                     f"{process.stderr} Code: {process.returncode}", exc_info=True |                     f"{process.stderr} Code: {process.returncode}", exc_info=True | ||||||
|                 ) |                 ) | ||||||
|  |  | ||||||
|             self.l_box.delete(self.select_tunnel[0]) |             self.list_box.delete(self.select_tunnel[0]) | ||||||
|             Path.unlink(f"{AppConfig.CONFIG_DIR}/{select_tl}.dat") |             Path.unlink(f"{AppConfig.CONFIG_DIR}/{select_tl}.dat") | ||||||
|  |  | ||||||
|             if select_tl == ConfigManager.get("autostart"): |             if select_tl == ConfigManager.get("autostart"): | ||||||
| @@ -774,7 +868,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|             self.wg_autostart.configure(state="disabled") |             self.wg_autostart.configure(state="disabled") | ||||||
|  |  | ||||||
|             # for disabling checkbox when Listbox empty |             # for disabling checkbox when Listbox empty | ||||||
|             if self.l_box.size() == 0: |             if self.list_box.size() == 0: | ||||||
|                 self.wg_autostart.configure(state="disabled") |                 self.wg_autostart.configure(state="disabled") | ||||||
|                 self.lb_rename.configure(state="disabled") |                 self.lb_rename.configure(state="disabled") | ||||||
|                 Tooltip( |                 Tooltip( | ||||||
| @@ -793,12 +887,12 @@ class FrameWidgets(ttk.Frame): | |||||||
|             if self.a != "" and self.a == select_tl: |             if self.a != "" and self.a == select_tl: | ||||||
|                 self.str_var.set(value="") |                 self.str_var.set(value="") | ||||||
|                 self.start() |                 self.start() | ||||||
|                 self.l_box.update() |                 self.list_box.update() | ||||||
|                 self.reset_fields() |                 self.reset_fields() | ||||||
|  |  | ||||||
|         except IndexError: |         except IndexError: | ||||||
|  |  | ||||||
|             if self.l_box.size() != 0: |             if self.list_box.size() != 0: | ||||||
|  |  | ||||||
|                 MessageDialog("info", Msg.STR["sel_list"], title=Msg.STR["sel_tl"]) |                 MessageDialog("info", Msg.STR["sel_list"], title=Msg.STR["sel_tl"]) | ||||||
|  |  | ||||||
| @@ -811,7 +905,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|         checkbox for enable autostart Tunnel |         checkbox for enable autostart Tunnel | ||||||
|         """ |         """ | ||||||
|         AppConfig.get_autostart_content() |         AppConfig.get_autostart_content() | ||||||
|         if self.l_box.size() != 0: |         if self.list_box.size() != 0: | ||||||
|             self.wg_autostart.configure(state="normal") |             self.wg_autostart.configure(state="normal") | ||||||
|             self.lb_rename.config(state="normal") |             self.lb_rename.config(state="normal") | ||||||
|             self.lb_rename.delete(0, tk.END) |             self.lb_rename.delete(0, tk.END) | ||||||
| @@ -838,13 +932,14 @@ class FrameWidgets(ttk.Frame): | |||||||
|         self.autoconnect_var.set(self.auto_con) |         self.autoconnect_var.set(self.auto_con) | ||||||
|  |  | ||||||
|         self.autoconnect = ttk.Label( |         self.autoconnect = ttk.Label( | ||||||
|             self.lb_frame3, |             self.autoconnect_frame, | ||||||
|             textvariable=self.autoconnect_var, |             textvariable=self.autoconnect_var, | ||||||
|             foreground="#0071ff", |             foreground="#0071ff", | ||||||
|             width=15, |             width=18, | ||||||
|         ) |         ) | ||||||
|         self.autoconnect.config(font=("Ubuntu", 11)) |         self.autoconnect.config(font=("Ubuntu", 11)) | ||||||
|         self.autoconnect.grid(column=1, row=0, sticky="e", pady=19) |         self.autoconnect.grid(column=1, row=0, sticky="ew", pady=19) | ||||||
|  |         self.autoconnect.rowconfigure(0, weight=1) | ||||||
|  |  | ||||||
|     def box_set(self) -> None: |     def box_set(self) -> None: | ||||||
|         """ |         """ | ||||||
| @@ -858,13 +953,13 @@ class FrameWidgets(ttk.Frame): | |||||||
|         to disable the autostart. |         to disable the autostart. | ||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             select_tunnel = self.l_box.curselection() |             select_tunnel = self.list_box.curselection() | ||||||
|             select_tl = self.l_box.get(select_tunnel[0]) |             select_tl = self.list_box.get(select_tunnel[0]) | ||||||
|  |  | ||||||
|             if self.selected_option.get() == 0: |             if self.selected_option.get() == 0: | ||||||
|                 ConfigManager.set("autostart", "off") |                 ConfigManager.set("autostart", "off") | ||||||
|  |  | ||||||
|                 if self.l_box.size() == 0: |                 if self.list_box.size() == 0: | ||||||
|                     self.wg_autostart.configure(state="disabled") |                     self.wg_autostart.configure(state="disabled") | ||||||
|  |  | ||||||
|             if self.selected_option.get() >= 1: |             if self.selected_option.get() >= 1: | ||||||
| @@ -906,8 +1001,8 @@ class FrameWidgets(ttk.Frame): | |||||||
|         else: |         else: | ||||||
|  |  | ||||||
|             try: |             try: | ||||||
|                 self.select_tunnel = self.l_box.curselection() |                 self.select_tunnel = self.list_box.curselection() | ||||||
|                 select_tl = self.l_box.get(self.select_tunnel[0]) |                 select_tl = self.list_box.get(self.select_tunnel[0]) | ||||||
|  |  | ||||||
|                 # nmcli connection modify old connection.id iphone |                 # nmcli connection modify old connection.id iphone | ||||||
|                 process: CompletedProcess[str] = run( |                 process: CompletedProcess[str] = run( | ||||||
| @@ -935,9 +1030,9 @@ class FrameWidgets(ttk.Frame): | |||||||
|                 if select_tl == ConfigManager.get("autostart"): |                 if select_tl == ConfigManager.get("autostart"): | ||||||
|                     ConfigManager.set("autostart", self.lb_rename.get()) |                     ConfigManager.set("autostart", self.lb_rename.get()) | ||||||
|                     self.autoconnect_var.set(value=self.lb_rename.get()) |                     self.autoconnect_var.set(value=self.lb_rename.get()) | ||||||
|                 self.l_box.delete(self.select_tunnel[0]) |                 self.list_box.delete(self.select_tunnel[0]) | ||||||
|                 self.l_box.insert("end", self.lb_rename.get()) |                 self.list_box.insert("end", self.lb_rename.get()) | ||||||
|                 self.l_box.update() |                 self.list_box.update() | ||||||
|                 self.lb_rename.delete(0, tk.END) |                 self.lb_rename.delete(0, tk.END) | ||||||
|                 self.update_connection_display() |                 self.update_connection_display() | ||||||
|  |  | ||||||
| @@ -968,34 +1063,36 @@ class FrameWidgets(ttk.Frame): | |||||||
|         in the UI using ttk.Label widgets. |         in the UI using ttk.Label widgets. | ||||||
|         Creates three labels for address, DNS, and endpoint with |         Creates three labels for address, DNS, and endpoint with | ||||||
|         specific styling (color, font), positioning them in a |         specific styling (color, font), positioning them in a | ||||||
|          grid layout (`lb_frame` and `lb_frame2`). |          grid layout (`lb_frame` and `peer_frame`). | ||||||
|         Each label is linked to a corresponding text variable |         Each label is linked to a corresponding text variable | ||||||
|         (`self.add`, `self.DNS`, `self.enp`) for dynamic data updates. |         (`self.add`, `self.DNS`, `self.enp`) for dynamic data updates. | ||||||
|         """ |         """ | ||||||
|         # Address Label |         # Address Label | ||||||
|         self.address = ttk.Label( |         self.address = ttk.Label( | ||||||
|             self.lb_frame, textvariable=self.add, foreground="#0071ff" |             self.interface_frame, textvariable=self.add, foreground="#0071ff" | ||||||
|         ) |         ) | ||||||
|         self.address.grid(column=0, row=5, sticky="w", padx=10, pady=6) |         self.address.grid(column=0, row=5, sticky="w", padx=10, pady=(0, 20)) | ||||||
|         self.address.config(font=("Ubuntu", 9)) |         self.address.config(font=("Ubuntu", 9)) | ||||||
|  |  | ||||||
|         # DNS Label |         # DNS Label | ||||||
|         self.dns = ttk.Label(self.lb_frame, textvariable=self.DNS, foreground="#0071ff") |         self.dns = ttk.Label( | ||||||
|         self.dns.grid(column=0, row=7, sticky="w", padx=10, pady=6) |             self.interface_frame, textvariable=self.DNS, foreground="#0071ff" | ||||||
|  |         ) | ||||||
|  |         self.dns.grid(column=0, row=7, sticky="w", padx=10, pady=(0, 20)) | ||||||
|         self.dns.config(font=("Ubuntu", 9)) |         self.dns.config(font=("Ubuntu", 9)) | ||||||
|  |  | ||||||
|         # Endpoint Label |         # Endpoint Label | ||||||
|         self.endpoint = ttk.Label( |         self.endpoint = ttk.Label( | ||||||
|             self.lb_frame2, textvariable=self.enp, foreground="#0071ff" |             self.peer_frame, textvariable=self.enp, foreground="#0071ff" | ||||||
|         ) |         ) | ||||||
|         self.endpoint.grid(column=0, row=8, sticky="w", padx=10, pady=20) |         self.endpoint.grid(column=0, row=8, sticky="w", padx=10, pady=(0, 30)) | ||||||
|         self.endpoint.config(font=("Ubuntu", 9)) |         self.endpoint.config(font=("Ubuntu", 9)) | ||||||
|  |  | ||||||
|     def wg_switch(self, event=None) -> None: |     def wg_switch(self, event=None) -> None: | ||||||
|         """ |         """ | ||||||
|         Manages switching between active and inactiveVPN connections. |         Manages switching between active and inactiveVPN connections. | ||||||
|         If no tunnel is selected (`self.a == ""`), it starts a new connection |         If no tunnel is selected (`self.a == ""`), it starts a new connection | ||||||
|         with the selected tunnel from the listbox (`l_box`). |         with the selected tunnel from the listbox (`list_box`). | ||||||
|         Otherwise, it stops the current connection and updates |         Otherwise, it stops the current connection and updates | ||||||
|         tunnel data using `handle_tunnel_data`. |         tunnel data using `handle_tunnel_data`. | ||||||
|         Handles errors like `IndexError` by displaying appropriate |         Handles errors like `IndexError` by displaying appropriate | ||||||
| @@ -1003,8 +1100,8 @@ class FrameWidgets(ttk.Frame): | |||||||
|         """ |         """ | ||||||
|         try: |         try: | ||||||
|             if self.a == "": |             if self.a == "": | ||||||
|                 self.select_tunnel = self.l_box.curselection() |                 self.select_tunnel = self.list_box.curselection() | ||||||
|                 select_tl = self.l_box.get(self.select_tunnel[0]) |                 select_tl = self.list_box.get(self.select_tunnel[0]) | ||||||
|                 self.handle_connection_state("start", select_tl) |                 self.handle_connection_state("start", select_tl) | ||||||
|  |  | ||||||
|             else: |             else: | ||||||
| @@ -1014,7 +1111,7 @@ class FrameWidgets(ttk.Frame): | |||||||
|  |  | ||||||
|         except IndexError: |         except IndexError: | ||||||
|  |  | ||||||
|             if self.l_box.size() != 0: |             if self.list_box.size() != 0: | ||||||
|  |  | ||||||
|                 MessageDialog("info", Msg.STR["sel_list"], title=Msg.STR["sel_tl"]) |                 MessageDialog("info", Msg.STR["sel_list"], title=Msg.STR["sel_tl"]) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,8 @@ | |||||||
| import logging | import logging | ||||||
| import gettext | import gettext | ||||||
| import locale | import locale | ||||||
|  | import tkinter as tk | ||||||
|  | import os | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| from subprocess import CompletedProcess, run | from subprocess import CompletedProcess, run | ||||||
| from typing import Dict, Any | from typing import Dict, Any | ||||||
| @@ -57,18 +59,18 @@ class AppConfig: | |||||||
|  |  | ||||||
|     # Updates |     # Updates | ||||||
|     # 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year |     # 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year | ||||||
|     VERSION: str = "v. 2.06.2425" |     VERSION: str = "v. 2.07.0225" | ||||||
|     UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases" |     UPDATE_URL: str = "https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases" | ||||||
|     DOWNLOAD_URL: str = "https://git.ilunix.de/punix/Wire-Py/archive" |     DOWNLOAD_URL: str = "https://git.ilunix.de/punix/Wire-Py/archive" | ||||||
|  |  | ||||||
|     # UI configuration |     # UI configuration | ||||||
|     UI_CONFIG: Dict[str, Any] = { |     UI_CONFIG: Dict[str, Any] = { | ||||||
|         "window_title": "Wire-Py", |         "window_title": "", | ||||||
|         "window_title2": "LogViewer", |         "window_title2": "LogViewer", | ||||||
|         "window_size": (600, 383), |         "window_size": (590, 460), | ||||||
|         "font_family": "Ubuntu", |         "font_family": "Ubuntu", | ||||||
|         "font_size": 11, |         "font_size": 11, | ||||||
|         "resizable_window": (False, False), |         "resizable_window": (True, True), | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     # System-dependent paths |     # System-dependent paths | ||||||
| @@ -79,20 +81,6 @@ class AppConfig: | |||||||
|         "pkey_path": "/usr/local/etc/ssl/pwgk.pem", |         "pkey_path": "/usr/local/etc/ssl/pwgk.pem", | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     # Images and icons paths |  | ||||||
|     IMAGE_PATHS: Dict[str, Path] = { |  | ||||||
|         "icon_vpn": "/usr/share/icons/lx-icons/48/wg_vpn.png", |  | ||||||
|         "icon_msg": "/usr/share/icons/lx-icons/48/wg_msg.png", |  | ||||||
|         "icon_import": "/usr/share/icons/lx-icons/48/wg_import.png", |  | ||||||
|         "icon_export": "/usr/share/icons/lx-icons/48/wg_export.png", |  | ||||||
|         "icon_trash": "/usr/share/icons/lx-icons/48/wg_trash.png", |  | ||||||
|         "icon_start": "/usr/share/icons/lx-icons/48/wg_vpn-start.png", |  | ||||||
|         "icon_stop": "/usr/share/icons/lx-icons/48/wg_vpn-stop.png", |  | ||||||
|         "icon_info": "/usr/share/icons/lx-icons/64/info.png", |  | ||||||
|         "icon_error": "/usr/share/icons/lx-icons/64/error.png", |  | ||||||
|         "icon_log": "/usr/share/icons/lx-icons/48/log.png", |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     @staticmethod |     @staticmethod | ||||||
|     def setup_translations() -> gettext.gettext: |     def setup_translations() -> gettext.gettext: | ||||||
|         """ |         """ | ||||||
| @@ -170,6 +158,65 @@ class AppConfig: | |||||||
| _ = AppConfig.setup_translations() | _ = AppConfig.setup_translations() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Image: | ||||||
|  |     def __init__(self): | ||||||
|  |         self.images = {} | ||||||
|  |  | ||||||
|  |     def load_image(self, image_key, fallback_paths=None) -> None | tk.PhotoImage: | ||||||
|  |         """Load PNG image using tk.PhotoImage with fallback options""" | ||||||
|  |         if image_key in self.images: | ||||||
|  |             return self.images[image_key] | ||||||
|  |  | ||||||
|  |         # Define image paths based on key | ||||||
|  |         image_paths = { | ||||||
|  |             "icon_header": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/32/wg_vpn.png", | ||||||
|  |             ], | ||||||
|  |             "icon_vpn": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_vpn.png", | ||||||
|  |             ], | ||||||
|  |             "icon_start": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_vpn-start.png", | ||||||
|  |             ], | ||||||
|  |             "icon_stop": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_vpn-stop.png", | ||||||
|  |             ], | ||||||
|  |             "icon_import": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_import.png", | ||||||
|  |             ], | ||||||
|  |             "icon_export": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_export.png", | ||||||
|  |             ], | ||||||
|  |             "icon_trash": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/48/wg_trash.png", | ||||||
|  |             ], | ||||||
|  |             "update": [ | ||||||
|  |                 "/usr/share/icons/lx-icons/16/settings.png", | ||||||
|  |             ], | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         # Get paths to try | ||||||
|  |         paths_to_try = image_paths.get(image_key, []) | ||||||
|  |  | ||||||
|  |         # Add fallback paths if provided | ||||||
|  |         if fallback_paths: | ||||||
|  |             paths_to_try.extend(fallback_paths) | ||||||
|  |  | ||||||
|  |         # Try to load image from paths | ||||||
|  |         for path in paths_to_try: | ||||||
|  |             try: | ||||||
|  |                 if os.path.exists(path): | ||||||
|  |                     photo = tk.PhotoImage(file=path) | ||||||
|  |                     self.images[image_key] = photo | ||||||
|  |                     return photo | ||||||
|  |             except tk.TclError as e: | ||||||
|  |                 print(f"Fail to load image {path}: {e}") | ||||||
|  |                 continue | ||||||
|  |  | ||||||
|  |         # Return None if no image found | ||||||
|  |         return None | ||||||
|  |  | ||||||
|  |  | ||||||
| class Msg: | class Msg: | ||||||
|     """ |     """ | ||||||
|     A utility class that provides centralized access to translated message strings. |     A utility class that provides centralized access to translated message strings. | ||||||
| @@ -193,6 +240,8 @@ class Msg: | |||||||
|  |  | ||||||
|     STR: Dict[str, str] = { |     STR: Dict[str, str] = { | ||||||
|         # Strings for messages |         # Strings for messages | ||||||
|  |         "header_left_bottom": _("Simple GUI for Wireguard"), | ||||||
|  |         "header_right_top": _("Wireguard VPN Manager"), | ||||||
|         "sel_tl": _("Select tunnel"), |         "sel_tl": _("Select tunnel"), | ||||||
|         "ren_err": _("Renaming not possible"), |         "ren_err": _("Renaming not possible"), | ||||||
|         "exp_succ": _("Export successful"), |         "exp_succ": _("Export successful"), | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user