04-06-2025_large_update #35
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "workbench.settings.openDefaultSettings": true
 | 
					    "workbench.settings.openDefaultSettings": true
 | 
				
			||||||
 | 
					    "workbench.startupEditor": "none"
 | 
				
			||||||
 | 
					    "update.showReleaseNotes": false
 | 
				
			||||||
 | 
					    "terminal.integrated.fontSize": 22
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										131
									
								
								cls_mth_fc.py
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								cls_mth_fc.py
									
									
									
									
									
								
							@@ -169,18 +169,6 @@ class LxTools(tk.Tk):
 | 
				
			|||||||
        if file is not None:
 | 
					        if file is not None:
 | 
				
			||||||
            Path.unlink(file)
 | 
					            Path.unlink(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def if_tip(path: Path) -> bool:
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        method that writes in file whether tooltip is displayed or not
 | 
					 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        lines = Path(path).read_text(encoding="utf-8")
 | 
					 | 
				
			||||||
        if "False\n" in lines:
 | 
					 | 
				
			||||||
            tip = False
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            tip = True
 | 
					 | 
				
			||||||
        return tip
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def msg_window(image_path: Path, image_path2: Path, w_title: str, w_txt: str, txt2: Optional[str] = None,
 | 
					    def msg_window(image_path: Path, image_path2: Path, w_title: str, w_txt: str, txt2: Optional[str] = None,
 | 
				
			||||||
                   com: Optional[str] = None) -> None:
 | 
					                   com: Optional[str] = None) -> None:
 | 
				
			||||||
@@ -382,6 +370,82 @@ class Tunnel:
 | 
				
			|||||||
            pass
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ConfigManager with caching
 | 
				
			||||||
 | 
					class ConfigManager:
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Universal class for managing configuration files with caching.
 | 
				
			||||||
 | 
					    Can be reused in different projects.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    _config = None
 | 
				
			||||||
 | 
					    _config_file = None
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def init(cls, config_file):
 | 
				
			||||||
 | 
					        """Initial the Configmanager with the given config file"""
 | 
				
			||||||
 | 
					        cls._config_file = config_file
 | 
				
			||||||
 | 
					        cls._config = None  # Reset the cache
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def load(cls):
 | 
				
			||||||
 | 
					        """Load the config file and return the config as dict"""
 | 
				
			||||||
 | 
					        if not cls._config:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                lines = Path(cls._config_file).read_text(encoding="utf-8").splitlines()
 | 
				
			||||||
 | 
					                cls._config = {
 | 
				
			||||||
 | 
					                    'updates': lines[1].strip(),
 | 
				
			||||||
 | 
					                    'theme': lines[3].strip(),
 | 
				
			||||||
 | 
					                    'tooltips': lines[5].strip() == 'True',
 | 
				
			||||||
 | 
					                    'autostart': lines[7].strip() if len(lines) > 7 else 'off'
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            except (IndexError, FileNotFoundError):
 | 
				
			||||||
 | 
					                # DeDefault values in case of error
 | 
				
			||||||
 | 
					                cls._config = {
 | 
				
			||||||
 | 
					                    'updates': 'on',
 | 
				
			||||||
 | 
					                    'theme': 'light',
 | 
				
			||||||
 | 
					                    'tooltips': True,
 | 
				
			||||||
 | 
					                    'autostart': 'off'
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					        return cls._config
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def save(cls):
 | 
				
			||||||
 | 
					        """Save the config to the config file"""
 | 
				
			||||||
 | 
					        if cls._config:
 | 
				
			||||||
 | 
					            lines = [
 | 
				
			||||||
 | 
					                '# Configuration\n',
 | 
				
			||||||
 | 
					                f"{cls._config['updates']}\n",
 | 
				
			||||||
 | 
					                '# Theme\n',
 | 
				
			||||||
 | 
					                f"{cls._config['theme']}\n",
 | 
				
			||||||
 | 
					                '# Tooltips\n',
 | 
				
			||||||
 | 
					                f"{str(cls._config['tooltips'])}\n",
 | 
				
			||||||
 | 
					                '# Autostart\n',
 | 
				
			||||||
 | 
					                f"{cls._config['autostart']}\n"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					            Path(cls._config_file).write_text(''.join(lines), encoding="utf-8")
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def set(cls, key, value):
 | 
				
			||||||
 | 
					        """Sets a configuration value and saves the change"""
 | 
				
			||||||
 | 
					        cls.load()
 | 
				
			||||||
 | 
					        cls._config[key] = value
 | 
				
			||||||
 | 
					        cls.save()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @classmethod
 | 
				
			||||||
 | 
					    def get(cls, key, default=None):
 | 
				
			||||||
 | 
					        """Returns a configuration value"""
 | 
				
			||||||
 | 
					        config = cls.load()
 | 
				
			||||||
 | 
					        return config.get(key, default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ThemeManager:
 | 
				
			||||||
 | 
					    @staticmethod
 | 
				
			||||||
 | 
					    def change_theme(root, theme_in_use, theme_name=None):
 | 
				
			||||||
 | 
					        """Change application theme centrally"""
 | 
				
			||||||
 | 
					        root.tk.call("set_theme", theme_in_use)
 | 
				
			||||||
 | 
					        if theme_in_use == theme_name:
 | 
				
			||||||
 | 
					            ConfigManager.set("theme", theme_in_use)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class GiteaUpdate:
 | 
					class GiteaUpdate:
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    Calling download requests the download URL of the running script,
 | 
					    Calling download requests the download URL of the running script,
 | 
				
			||||||
@@ -390,35 +454,46 @@ class GiteaUpdate:
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def api_down(update_api_url: str, version: str, file: Optional[Path] = None) -> str:
 | 
					    def api_down(update_api_url: str, version: str, update_setting: str = None) -> str:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Checks for updates via API
 | 
					        Checks for updates via API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            update_api_url: Update API URL
 | 
					            update_api_url: Update API URL
 | 
				
			||||||
            version: Current version
 | 
					            version: Current version
 | 
				
			||||||
            file: Optional - Configuration file
 | 
					            update_setting: Update setting from ConfigManager (on/off)
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        Returns:
 | 
					        Returns:
 | 
				
			||||||
            New version or status message
 | 
					            New version or status message
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        # If updates are disabled, return immediately
 | 
				
			||||||
 | 
					        if update_setting != "on":
 | 
				
			||||||
 | 
					            return "False"
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            response: requests.Response = requests.get(update_api_url, timeout=10)
 | 
					            response: requests.Response = requests.get(update_api_url, timeout=10)
 | 
				
			||||||
            response_dict: Any = response.json()
 | 
					            response.raise_for_status()  # Raise exception for HTTP errors
 | 
				
			||||||
            response_dict: Dict[str, Any] = response_dict[0]
 | 
					            
 | 
				
			||||||
            with open(file, "r", encoding="utf-8") as set_f:
 | 
					            response_data = response.json()
 | 
				
			||||||
                set_f = set_f.read()
 | 
					            if not response_data:
 | 
				
			||||||
                if "on\n" in set_f:
 | 
					                return "No Updates"
 | 
				
			||||||
                    if version[3:] != response_dict["tag_name"]:
 | 
					                
 | 
				
			||||||
                        req: str = response_dict["tag_name"]
 | 
					            latest_version = response_data[0].get("tag_name")
 | 
				
			||||||
                    else:
 | 
					            if not latest_version:
 | 
				
			||||||
                        req: str = "No Updates"
 | 
					                return "Invalid API Response"
 | 
				
			||||||
                else:
 | 
					                
 | 
				
			||||||
                    req: str = "False"
 | 
					            # Compare versions (strip 'v. ' prefix if present)
 | 
				
			||||||
                return req
 | 
					            current_version = version[3:] if version.startswith("v. ") else version
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            if current_version != latest_version:
 | 
				
			||||||
 | 
					                return latest_version
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return "No Updates"
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
        except requests.exceptions.RequestException:
 | 
					        except requests.exceptions.RequestException:
 | 
				
			||||||
            req: str = "No Internet Connection!"
 | 
					            return "No Internet Connection!"
 | 
				
			||||||
            return req
 | 
					        except (ValueError, KeyError, IndexError):
 | 
				
			||||||
 | 
					            return "Invalid API Response"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def download(urld: str, res: str, image_path: Path = None, image_path2: Path = None, image_path3: Path = None, 
 | 
					    def download(urld: str, res: str, image_path: Path = None, image_path2: Path = None, image_path3: Path = None, 
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										437
									
								
								wirepy.py
									
									
									
									
									
								
							
							
						
						
									
										437
									
								
								wirepy.py
									
									
									
									
									
								
							@@ -14,17 +14,13 @@ from pathlib import Path
 | 
				
			|||||||
from subprocess import check_call
 | 
					from subprocess import check_call
 | 
				
			||||||
from tkinter import TclError, filedialog, ttk
 | 
					from tkinter import TclError, filedialog, ttk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from cls_mth_fc import (Create, GiteaUpdate, Tunnel, Tooltip, LxTools)
 | 
					from cls_mth_fc import (ConfigManager, ThemeManager, Create, GiteaUpdate, Tunnel, Tooltip, LxTools)
 | 
				
			||||||
from wp_app_config import AppConfig, Msg
 | 
					from wp_app_config import AppConfig, Msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LxTools.uos()
 | 
					LxTools.uos()
 | 
				
			||||||
Create.dir_and_files()
 | 
					Create.dir_and_files()
 | 
				
			||||||
Create.make_dir()
 | 
					Create.make_dir()
 | 
				
			||||||
Create.decrypt()
 | 
					Create.decrypt()
 | 
				
			||||||
# 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
 | 
					 | 
				
			||||||
VERSION: str = "v. 2.04.1725"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
res = GiteaUpdate.api_down("https://git.ilunix.de/api/v1/repos/punix/Wire-Py/releases", VERSION, AppConfig.SETTINGS_FILE)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Wirepy(tk.Tk):
 | 
					class Wirepy(tk.Tk):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
@@ -43,22 +39,17 @@ class Wirepy(tk.Tk):
 | 
				
			|||||||
        self.geometry(f"{self.x_width}x{self.y_height}+{self.monitor_center_x}+{self.monitor_center_y}")
 | 
					        self.geometry(f"{self.x_width}x{self.y_height}+{self.monitor_center_x}+{self.monitor_center_y}")
 | 
				
			||||||
        self.columnconfigure(0, weight=1)
 | 
					        self.columnconfigure(0, weight=1)
 | 
				
			||||||
        self.rowconfigure(0, weight=1)
 | 
					        self.rowconfigure(0, weight=1)
 | 
				
			||||||
        self.style = ttk.Style(self)
 | 
					 | 
				
			||||||
        self.tk.call("source", f"{AppConfig.SYSTEM_PATHS["tcl_path"]}/water.tcl")
 | 
					        self.tk.call("source", f"{AppConfig.SYSTEM_PATHS["tcl_path"]}/water.tcl")
 | 
				
			||||||
        lines = AppConfig.SETTINGS_FILE.read_text()
 | 
					        ConfigManager.init(AppConfig.SETTINGS_FILE)
 | 
				
			||||||
        if "light\n" in lines:
 | 
					        theme = ConfigManager.get("theme")
 | 
				
			||||||
            self.tk.call("set_theme", "light")
 | 
					        ThemeManager.change_theme(self, theme)
 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            self.tk.call("set_theme", "dark")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Load the image file from the disk
 | 
					        # Load the image file from the disk
 | 
				
			||||||
        self.wg_icon = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"])
 | 
					        self.wg_icon = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_vpn"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Set it as the window icon
 | 
					        # Set it as the window icon
 | 
				
			||||||
        self.iconphoto(True, self.wg_icon)
 | 
					        self.iconphoto(True, self.wg_icon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        tips = LxTools.if_tip(AppConfig.SETTINGS_FILE)
 | 
					        FrameWidgets(self).grid()
 | 
				
			||||||
        FrameWidgets(self, tips_enabled=tips).grid()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FrameWidgets(ttk.Frame):
 | 
					class FrameWidgets(ttk.Frame):
 | 
				
			||||||
@@ -68,47 +59,59 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
    def __init__(self, container, tips_enabled=None, **kwargs):
 | 
					    def __init__(self, container, tips_enabled=None, **kwargs):
 | 
				
			||||||
        super().__init__(container, **kwargs)
 | 
					        super().__init__(container, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.tunnel = Tunnel()
 | 
					 | 
				
			||||||
        self.lb_tunnel = None
 | 
					        self.lb_tunnel = None
 | 
				
			||||||
        self.btn_stst = None
 | 
					        self.btn_stst = None
 | 
				
			||||||
        self.endpoint = None
 | 
					        self.endpoint = None
 | 
				
			||||||
        self.dns = None
 | 
					        self.dns = None
 | 
				
			||||||
        self.address = None
 | 
					        self.address = None
 | 
				
			||||||
        self.auto_con = None
 | 
					        self.auto_con = None
 | 
				
			||||||
 | 
					        self.tips_enabled = tips_enabled
 | 
				
			||||||
 | 
					        self.style = ttk.Style()
 | 
				
			||||||
        self.wg_vpn_start = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_start"])
 | 
					        self.wg_vpn_start = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_start"])
 | 
				
			||||||
        self.wg_vpn_stop = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_stop"])
 | 
					        self.wg_vpn_stop = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_stop"])
 | 
				
			||||||
        self.imp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_import"])
 | 
					        self.imp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_import"])
 | 
				
			||||||
        self.tr_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_trash"])
 | 
					        self.tr_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_trash"])
 | 
				
			||||||
        self.exp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_export"])
 | 
					        self.exp_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_export"])
 | 
				
			||||||
        self.warning_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_error"])
 | 
					        self.warning_pic = tk.PhotoImage(file=AppConfig.IMAGE_PATHS["icon_error"])
 | 
				
			||||||
        self.tips_enabled = tips_enabled if tips_enabled is not None else LxTools.if_tip(AppConfig.SETTINGS_FILE)
 | 
					        self.tips_enabled = tips_enabled if tips_enabled is not None else ConfigManager.get("tooltip")
 | 
				
			||||||
 | 
					        # StringVar-Variables initialization
 | 
				
			||||||
 | 
					        self.update_label = tk.StringVar()
 | 
				
			||||||
 | 
					        self.update_tooltip = tk.StringVar()
 | 
				
			||||||
 | 
					        self.update_foreground = tk.StringVar(value="red")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # 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.configure(relief="flat")
 | 
				
			||||||
        self.menu_frame.grid(column=0, row=0, columnspan=4, sticky="w")
 | 
					        self.menu_frame.grid(column=0, row=0, columnspan=4, sticky="w")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # App Menu
 | 
					        # App Menu
 | 
				
			||||||
        self.version_lb = ttk.Label(self.menu_frame, text=VERSION)
 | 
					        self.version_lb = ttk.Label(self.menu_frame, text=AppConfig.VERSION)
 | 
				
			||||||
        self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff")
 | 
					        self.version_lb.config(font=("Ubuntu", 11), foreground="#00c4ff")
 | 
				
			||||||
        self.version_lb.grid(column=0, row=0, rowspan=4, padx=10)
 | 
					        self.version_lb.grid(column=0, row=0, rowspan=4, padx=10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Tooltip(self.version_lb, f"Version: {VERSION[2:]}", self.tips_enabled)
 | 
					        Tooltip(self.version_lb, f"Version: {AppConfig.VERSION[2:]}", self.tips_enabled)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        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=1, columnspan=1, row=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Tooltip(self.options_btn, _("Click for Settings"), self.tips_enabled)
 | 
					        Tooltip(self.options_btn, _("Click for Settings"), self.tips_enabled)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        set_update = tk.IntVar()
 | 
					        self.set_update = tk.IntVar()
 | 
				
			||||||
        set_tip = tk.BooleanVar()
 | 
					        self.set_tip = tk.BooleanVar()
 | 
				
			||||||
        self.settings = tk.Menu(self, relief="flat")
 | 
					        self.settings = tk.Menu(self, relief="flat")
 | 
				
			||||||
        self.options_btn.configure(menu=self.settings, style="Toolbutton")
 | 
					        self.options_btn.configure(menu=self.settings, style="Toolbutton")
 | 
				
			||||||
        self.settings.add_checkbutton(label=_("Disable Updates"),
 | 
					        self.settings.add_checkbutton(label=_("Disable Updates"),
 | 
				
			||||||
                                      command=lambda: self.update_setting(set_update.get()), variable=set_update)
 | 
					                                      command=lambda: self.update_setting(self.set_update.get()), variable=self.set_update)
 | 
				
			||||||
        self.settings.add_checkbutton(label=_("Disable Tooltips"),
 | 
					        self.settings.add_command(label=_("Disable Tooltips"),
 | 
				
			||||||
                                      command=lambda: self.tooltip(set_tip.get()), variable=set_tip)
 | 
					                                      command=lambda: self.tooltip(self.set_tip.get()), variable=self.set_tip)
 | 
				
			||||||
        self.settings.add_command(label=_("Light"), command=self.theme_change_light)
 | 
					
 | 
				
			||||||
        self.settings.add_command(label=_("Dark"), command=self.theme_change_dark)
 | 
					        self.updates_lb = ttk.Label(self.menu_frame)
 | 
				
			||||||
 | 
					        res = GiteaUpdate.api_down(AppConfig.UPDATE_URL, AppConfig.VERSION, ConfigManager.get("updates"))
 | 
				
			||||||
 | 
					        self.update_ui_for_update(res)
 | 
				
			||||||
 | 
					        # Label show dark or light  
 | 
				
			||||||
 | 
					        self.theme_label = tk.StringVar()
 | 
				
			||||||
 | 
					        self.update_theme_label()                           
 | 
				
			||||||
 | 
					        self.settings.add_command(label=self.theme_label.get(), command=self.on_theme_toggle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # About BTN Menu / Label
 | 
					        # About BTN Menu / Label
 | 
				
			||||||
        self.about_btn = ttk.Button(
 | 
					        self.about_btn = ttk.Button(
 | 
				
			||||||
@@ -116,49 +119,10 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
        self.about_btn.grid(column=2, columnspan=2, row=0)
 | 
					        self.about_btn.grid(column=2, columnspan=2, row=0)
 | 
				
			||||||
        self.readme = tk.Menu(self)
 | 
					        self.readme = tk.Menu(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Update and Tooltip Label
 | 
					 | 
				
			||||||
        self.updates_lb = ttk.Label(self.menu_frame)
 | 
					 | 
				
			||||||
        self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # View Checkbox to enable or disable Tooltip
 | 
					        # View Checkbox to enable or disable Tooltip
 | 
				
			||||||
        if tips:
 | 
					        self.set_tip.set(value=not self.tips_enabled)
 | 
				
			||||||
            set_tip.set(value=False)
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            set_tip.set(value=True)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # View Checkbox for enable or disable Updates
 | 
					 | 
				
			||||||
        if res == "False":
 | 
					 | 
				
			||||||
            set_update.set(value=1)
 | 
					 | 
				
			||||||
            self.updates_lb.configure(text=_("Update search off"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Tooltip(self.updates_lb, _("Updates you have disabled"), self.tips_enabled)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        elif res == "No Internet Connection!":
 | 
					 | 
				
			||||||
            self.updates_lb.configure(text=_("No Server Connection!"), foreground="red")
 | 
					 | 
				
			||||||
        elif res == "No Updates":
 | 
					 | 
				
			||||||
            self.updates_lb.configure(text=_("No Updates"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Tooltip(self.updates_lb, _("Congratulations! Wire-Py is up to date"), self.tips_enabled)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            set_update.set(value=0)
 | 
					 | 
				
			||||||
            text = f"Update {res} {_("available!")}"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            # Update BTN Menu
 | 
					 | 
				
			||||||
            self.update_btn = ttk.Menubutton(self.menu_frame, text=text)
 | 
					 | 
				
			||||||
            self.update_btn.grid(column=4, columnspan=3, row=0, padx=0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            Tooltip(self.update_btn, _("Click to download new version"), self.tips_enabled)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.download = tk.Menu(self, relief="flat")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            self.update_btn.configure(menu=self.download, style="Toolbutton")
 | 
					 | 
				
			||||||
            self.download.add_command(
 | 
					 | 
				
			||||||
                label=_("Download"),
 | 
					 | 
				
			||||||
                command=lambda: GiteaUpdate.download(f"https://git.ilunix.de/punix/Wire-Py/archive/{res}.zip", 
 | 
					 | 
				
			||||||
                                                    res, AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"]))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Show active Tunnel
 | 
					 | 
				
			||||||
        self.a = Tunnel.active()
 | 
					        self.a = Tunnel.active()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Label Frame 1
 | 
					        # Label Frame 1
 | 
				
			||||||
@@ -254,8 +218,11 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # Button Export
 | 
					        # Button Export
 | 
				
			||||||
        self.btn_exp = ttk.Button(self.lb_frame_btn_lbox, image=self.exp_pic,
 | 
					        self.btn_exp = ttk.Button(self.lb_frame_btn_lbox, image=self.exp_pic,
 | 
				
			||||||
                                  command=lambda: Tunnel.export(AppConfig.IMAGE_PATHS["icon_info"], AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_error"], AppConfig.IMAGE_PATHS["icon_msg"],
 | 
					                                  command=lambda: Tunnel.export(AppConfig.IMAGE_PATHS["icon_info"], 
 | 
				
			||||||
 | 
					                                  AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_error"], 
 | 
				
			||||||
 | 
					                                  AppConfig.IMAGE_PATHS["icon_msg"],
 | 
				
			||||||
                                  Msg.STR["sel_tl"], Msg.STR["tl_first"]), padding=0)
 | 
					                                  Msg.STR["sel_tl"], Msg.STR["tl_first"]), padding=0)
 | 
				
			||||||
 | 
					                                  
 | 
				
			||||||
        self.btn_exp.grid(column=0, row=3, padx=15, pady=8)
 | 
					        self.btn_exp.grid(column=0, row=3, padx=15, pady=8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.l_box.size() == 0:
 | 
					        if self.l_box.size() == 0:
 | 
				
			||||||
@@ -304,40 +271,97 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.on_off()
 | 
					        self.on_off()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Update the labels based on the result
 | 
				
			||||||
 | 
					    def update_ui_for_update(self, res):
 | 
				
			||||||
 | 
					        """Update UI elements based on update check result"""
 | 
				
			||||||
 | 
					        if res == "False":
 | 
				
			||||||
 | 
					            self.set_update.set(value=1)
 | 
				
			||||||
 | 
					            self.update_label.set(_("Update search off"))
 | 
				
			||||||
 | 
					            self.update_tooltip.set(_("Updates you have disabled"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("red")
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
    @staticmethod
 | 
					            # Remove update button if it exists
 | 
				
			||||||
    def update_setting(update_res) -> None:
 | 
					            if hasattr(self, 'update_btn'):
 | 
				
			||||||
        """
 | 
					                self.update_btn.grid_forget()
 | 
				
			||||||
        write off or on in file
 | 
					                
 | 
				
			||||||
        Args:
 | 
					            # Display the label
 | 
				
			||||||
            update_res (int): argument that is passed contains 0 or 1
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
        """
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
        if update_res == 1:
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
 | 
					            )
 | 
				
			||||||
            lines[1] = 'off\n' 
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					            Tooltip(self.updates_lb, self.update_tooltip.get(), self.tips_enabled)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        elif res == "No Internet Connection!":
 | 
				
			||||||
 | 
					            self.update_label.set(_("No Server Connection!"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("red")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Remove update button if it exists
 | 
				
			||||||
 | 
					            if hasattr(self, 'update_btn'):
 | 
				
			||||||
 | 
					                self.update_btn.grid_forget()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            # Display the label
 | 
				
			||||||
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        elif res == "No Updates":
 | 
				
			||||||
 | 
					            self.update_label.set(_("No Updates"))
 | 
				
			||||||
 | 
					            self.update_tooltip.set(_("Congratulations! Wire-Py is up to date"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("black")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Remove update button if it exists
 | 
				
			||||||
 | 
					            if hasattr(self, 'update_btn'):
 | 
				
			||||||
 | 
					                self.update_btn.grid_forget()
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					            # Display the label
 | 
				
			||||||
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
 | 
					            Tooltip(self.updates_lb, self.update_tooltip.get(), self.tips_enabled)
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
 | 
					            self.set_update.set(value=0)
 | 
				
			||||||
            lines[1] = 'on\n' 
 | 
					            update_text = f"Update {res} {_('available!')}"
 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
    @staticmethod
 | 
					            # Remove the label if displayed
 | 
				
			||||||
    def tooltip(tip) -> None:
 | 
					            self.updates_lb.grid_forget()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Create or update the update button
 | 
				
			||||||
 | 
					            if not hasattr(self, 'update_btn'):
 | 
				
			||||||
 | 
					                # Create the update button if it doesn't exist yet
 | 
				
			||||||
 | 
					                self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text)
 | 
				
			||||||
 | 
					                self.update_btn.grid(column=4, columnspan=3, row=0, padx=0)
 | 
				
			||||||
 | 
					                Tooltip(self.update_btn, _("Click to download new version"), self.tips_enabled)
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                self.download = tk.Menu(self, relief="flat")
 | 
				
			||||||
 | 
					                self.update_btn.configure(menu=self.download, style="Toolbutton")
 | 
				
			||||||
 | 
					                self.download.add_command(
 | 
				
			||||||
 | 
					                    label=_("Download"),
 | 
				
			||||||
 | 
					                    command=lambda: GiteaUpdate.download(
 | 
				
			||||||
 | 
					                        f"{AppConfig.DOWNLOAD_URL}/{res}.zip",
 | 
				
			||||||
 | 
					                        res, 
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_info"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_vpn"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_error"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_msg"]
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					}  
 | 
				
			||||||
 | 
					    def tooltip(self, tip) -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        write True or False in a file
 | 
					        Aktualisiert die Tooltip-Einstellung im ConfigManager
 | 
				
			||||||
        Args:
 | 
					        Args:
 | 
				
			||||||
            tip (bool): argument that is passed contains True or False
 | 
					            tip (bool): True zum Deaktivieren, False zum Aktivieren von Tooltips
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if tip:
 | 
					        # Beachten Sie die umgekehrte Logik: tip=True bedeutet Tooltips deaktivieren
 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
 | 
					        ConfigManager.set("tooltip", not tip)
 | 
				
			||||||
            lines[5] = 'False\n' 
 | 
					        # Aktualisieren Sie die lokale Variable für sofortige Wirkung
 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					        self.tips_enabled = not tip
 | 
				
			||||||
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
 | 
					 | 
				
			||||||
            lines[5] = 'True\n' 
 | 
					 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					    @staticmethod
 | 
				
			||||||
    def about() -> None:
 | 
					    def about() -> None:
 | 
				
			||||||
@@ -354,27 +378,163 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_vpn"], _("Info"), msg_t, _("Go to Wire-Py git"), link_btn)
 | 
					        LxTools.msg_window(AppConfig.IMAGE_PATHS["icon_vpn"], AppConfig.IMAGE_PATHS["icon_vpn"], _("Info"), msg_t, _("Go to Wire-Py git"), link_btn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def theme_change_light(self) -> None:
 | 
					    def update_ui_for_update_status(self, res):
 | 
				
			||||||
        """
 | 
					        """Update UI elements based on update check result"""
 | 
				
			||||||
        Set a light theme
 | 
					        print(f"Updating UI for result: {res}")  # Debug output
 | 
				
			||||||
        """
 | 
					 | 
				
			||||||
        if self.tk.call("ttk::style", "theme", "use") == "water-dark":
 | 
					 | 
				
			||||||
            self.tk.call("set_theme", "light")
 | 
					 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)  # (keepends=True) = not changed
 | 
					 | 
				
			||||||
            lines[3] = 'light\n' 
 | 
					 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					 | 
				
			||||||
            self.color_label()
 | 
					 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
    def theme_change_dark(self) -> None:
 | 
					        # First, clean up any existing UI elements
 | 
				
			||||||
 | 
					        if hasattr(self, 'update_btn') and self.update_btn.winfo_exists():
 | 
				
			||||||
 | 
					            self.update_btn.grid_forget()
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        # Reset all variables to ensure fresh state
 | 
				
			||||||
 | 
					        self.update_label.set("")
 | 
				
			||||||
 | 
					        self.update_tooltip.set("")
 | 
				
			||||||
 | 
					        self.update_foreground.set("black")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if res == "False":
 | 
				
			||||||
 | 
					            self.set_update.set(value=1)
 | 
				
			||||||
 | 
					            self.update_label.set(_("Update search off"))
 | 
				
			||||||
 | 
					            self.update_tooltip.set(_("Updates you have disabled"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("red")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Display the label
 | 
				
			||||||
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
 | 
					            Tooltip(self.updates_lb, self.update_tooltip.get(), self.tips_enabled)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        elif res == "No Internet Connection!":
 | 
				
			||||||
 | 
					            self.update_label.set(_("No Server Connection!"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("red")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Display the label
 | 
				
			||||||
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        elif res == "No Updates":
 | 
				
			||||||
 | 
					            self.update_label.set(_("No Updates"))
 | 
				
			||||||
 | 
					            self.update_tooltip.set(_("Congratulations! Wire-Py is up to date"))
 | 
				
			||||||
 | 
					            self.update_foreground.set("black")
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Display the label
 | 
				
			||||||
 | 
					            self.updates_lb.configure(
 | 
				
			||||||
 | 
					                textvariable=self.update_label,
 | 
				
			||||||
 | 
					                foreground=self.update_foreground.get()
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            self.updates_lb.grid(column=4, columnspan=3, row=0, padx=10)
 | 
				
			||||||
 | 
					            Tooltip(self.updates_lb, self.update_tooltip.get(), self.tips_enabled)
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # We have an update available
 | 
				
			||||||
 | 
					            self.set_update.set(value=0)
 | 
				
			||||||
 | 
					            update_text = f"Update {res} {_('available!')}"
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Hide the label if it's visible
 | 
				
			||||||
 | 
					            if self.updates_lb.winfo_ismapped():
 | 
				
			||||||
 | 
					                self.updates_lb.grid_forget()
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            # Create or update the update button
 | 
				
			||||||
 | 
					            if not hasattr(self, 'update_btn') or not self.update_btn.winfo_exists():
 | 
				
			||||||
 | 
					                # Create the update button if it doesn't exist yet
 | 
				
			||||||
 | 
					                self.update_btn = ttk.Menubutton(self.menu_frame, text=update_text)
 | 
				
			||||||
 | 
					                self.update_btn.grid(column=4, columnspan=3, row=0, padx=0)
 | 
				
			||||||
 | 
					                Tooltip(self.update_btn, _("Click to download new version"), self.tips_enabled)
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                self.download = tk.Menu(self, relief="flat")
 | 
				
			||||||
 | 
					                self.update_btn.configure(menu=self.download, style="Toolbutton")
 | 
				
			||||||
 | 
					                self.download.add_command(
 | 
				
			||||||
 | 
					                    label=_("Download"),
 | 
				
			||||||
 | 
					                    command=lambda: GiteaUpdate.download(
 | 
				
			||||||
 | 
					                        f"{AppConfig.DOWNLOAD_URL}/{res}.zip",
 | 
				
			||||||
 | 
					                        res, 
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_info"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_vpn"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_error"],
 | 
				
			||||||
 | 
					                        AppConfig.IMAGE_PATHS["icon_msg"]
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # Update the existing update button
 | 
				
			||||||
 | 
					                self.update_btn.configure(text=update_text)
 | 
				
			||||||
 | 
					                # Make sure it's visible
 | 
				
			||||||
 | 
					                self.update_btn.grid(column=4, columnspan=3, row=0, padx=0)
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                # Update the download command
 | 
				
			||||||
 | 
					                if hasattr(self, 'download'):
 | 
				
			||||||
 | 
					                    self.download.entryconfigure(
 | 
				
			||||||
 | 
					                        0,  # First entry in the menu
 | 
				
			||||||
 | 
					                        command=lambda: GiteaUpdate.download(
 | 
				
			||||||
 | 
					                            f"{AppConfig.DOWNLOAD_URL}/{res}.zip",
 | 
				
			||||||
 | 
					                            res, 
 | 
				
			||||||
 | 
					                            AppConfig.IMAGE_PATHS["icon_info"],
 | 
				
			||||||
 | 
					                            AppConfig.IMAGE_PATHS["icon_vpn"],
 | 
				
			||||||
 | 
					                            AppConfig.IMAGE_PATHS["icon_error"],
 | 
				
			||||||
 | 
					                            AppConfig.IMAGE_PATHS["icon_msg"]
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_setting(self, update_res) -> None:
 | 
				
			||||||
 | 
					        """write off or on in file
 | 
				
			||||||
 | 
					        Args:
 | 
				
			||||||
 | 
					            update_res (int): argument that is passed contains 0 or 1
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Set a dark theme
 | 
					        if update_res == 1:
 | 
				
			||||||
        """
 | 
					            # Disable updates
 | 
				
			||||||
        if not self.tk.call("ttk::style", "theme", "use") == "water-dark":
 | 
					            ConfigManager.set("updates", "off")
 | 
				
			||||||
            self.tk.call("set_theme", "dark")
 | 
					            # When updates are disabled, we know the result should be "False"
 | 
				
			||||||
            lines = Path(AppConfig.SETTINGS_FILE).read_text(encoding="utf-8").splitlines(keepends=True)
 | 
					            self.update_ui_for_update_status("False")
 | 
				
			||||||
            lines[3] = 'dark\n' 
 | 
					        else:
 | 
				
			||||||
            Path(AppConfig.SETTINGS_FILE).write_text(''.join(lines), encoding="utf-8")
 | 
					            # Enable updates
 | 
				
			||||||
            self.color_label()
 | 
					            ConfigManager.set("updates", "on")
 | 
				
			||||||
 | 
					            # When enabling updates, we need to actually check for updates
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                # Force a fresh check by passing "on" as the update setting
 | 
				
			||||||
 | 
					                res = GiteaUpdate.api_down(AppConfig.UPDATE_URL, AppConfig.VERSION, "on")
 | 
				
			||||||
 | 
					                print(f"API returned: {res}")  # Debug output
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                # Make sure UI is updated regardless of previous state
 | 
				
			||||||
 | 
					                if hasattr(self, 'update_btn'):
 | 
				
			||||||
 | 
					                    self.update_btn.grid_forget()
 | 
				
			||||||
 | 
					                if hasattr(self, 'updates_lb'):
 | 
				
			||||||
 | 
					                    self.updates_lb.grid_forget()
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                # Now update the UI with the fresh result
 | 
				
			||||||
 | 
					                self.update_ui_for_update_status(res)
 | 
				
			||||||
 | 
					            except Exception as e:
 | 
				
			||||||
 | 
					                print(f"Error checking for updates: {e}")
 | 
				
			||||||
 | 
					                # Fallback to a default message if there's an error
 | 
				
			||||||
 | 
					                self.update_ui_for_update_status("No Internet Connection!")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_tooletip_label(self) -> str:
 | 
				
			||||||
 | 
					        """Update the theme label based on current theme"""
 | 
				
			||||||
 | 
					        current_value = ConfigManager.get("tooletip")
 | 
				
			||||||
 | 
					        if current_value == "True": 
 | 
				
			||||||
 | 
					            self.set_tip.set(_("Enable Tooltips"))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.set_tip.set(_("Disable Tooltips"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update_theme_label(self) -> str:
 | 
				
			||||||
 | 
					        """Update the theme label based on current theme"""
 | 
				
			||||||
 | 
					        current_theme = ConfigManager.get("theme")
 | 
				
			||||||
 | 
					        if current_theme == "light":
 | 
				
			||||||
 | 
					            self.theme_label.set(_("Dark"))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.theme_label.set(_("Light"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_theme_toggle(self) -> None:
 | 
				
			||||||
 | 
					        """Toggle between light and dark theme"""
 | 
				
			||||||
 | 
					        current_theme = ConfigManager.get("theme")
 | 
				
			||||||
 | 
					        new_theme = "dark" if current_theme == "light" else "light"
 | 
				
			||||||
 | 
					        ThemeManager.change_theme(self, new_theme, new_theme)
 | 
				
			||||||
 | 
					        self.color_label()
 | 
				
			||||||
 | 
					        self.update_theme_label()  # Update the theme label
 | 
				
			||||||
 | 
					        # Update Menulfield
 | 
				
			||||||
 | 
					        self.settings.entryconfigure(2, label=self.theme_label.get())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def start(self) -> None:
 | 
					    def start(self) -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@@ -410,8 +570,8 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        View activ Tunnel in the color green or yellow
 | 
					        View activ Tunnel in the color green or yellow
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        lines = AppConfig.SETTINGS_FILE.read_text()
 | 
					        if  ConfigManager.get("theme") == "light":
 | 
				
			||||||
        if "light\n" in lines:
 | 
					            
 | 
				
			||||||
            self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green")
 | 
					            self.lb_tunnel = ttk.Label(self, textvariable=self.str_var, foreground="green")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
@@ -727,54 +887,6 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
            except EOFError as e:
 | 
					            except EOFError as e:
 | 
				
			||||||
                print(e)
 | 
					                print(e)
 | 
				
			||||||
                  
 | 
					                  
 | 
				
			||||||
    def activate_tunnel(self, tunnel_name):
 | 
					 | 
				
			||||||
        """Activates a tunnel after a delay"""
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            # First check if the tunnel exists in NetworkManager
 | 
					 | 
				
			||||||
            nm_connections = subprocess.run(
 | 
					 | 
				
			||||||
                ["nmcli", "-t", "-f", "NAME", "connection", "show"],
 | 
					 | 
				
			||||||
                check=True,
 | 
					 | 
				
			||||||
                stdout=subprocess.PIPE,
 | 
					 | 
				
			||||||
                text=True
 | 
					 | 
				
			||||||
            ).stdout.strip().split('\n')
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            # Find the actual connection name (it might have been modified)
 | 
					 | 
				
			||||||
            actual_name = None
 | 
					 | 
				
			||||||
            for conn in nm_connections:
 | 
					 | 
				
			||||||
                if tunnel_name in conn:
 | 
					 | 
				
			||||||
                    actual_name = conn
 | 
					 | 
				
			||||||
                    break
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            if actual_name:
 | 
					 | 
				
			||||||
                # Use the actual connection name
 | 
					 | 
				
			||||||
                subprocess.run(["nmcli", "connection", "up", actual_name], 
 | 
					 | 
				
			||||||
                            check=True, 
 | 
					 | 
				
			||||||
                            stdout=subprocess.PIPE, 
 | 
					 | 
				
			||||||
                            stderr=subprocess.PIPE)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                # Use the original name as fallback
 | 
					 | 
				
			||||||
                subprocess.run(["nmcli", "connection", "up", tunnel_name], 
 | 
					 | 
				
			||||||
                            check=True, 
 | 
					 | 
				
			||||||
                            stdout=subprocess.PIPE, 
 | 
					 | 
				
			||||||
                            stderr=subprocess.PIPE)
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            # After successful activation, update the display
 | 
					 | 
				
			||||||
            self.a = Tunnel.active()
 | 
					 | 
				
			||||||
            self.str_var.set(self.a)
 | 
					 | 
				
			||||||
            self.color_label()
 | 
					 | 
				
			||||||
            
 | 
					 | 
				
			||||||
            # Try to load the tunnel data
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                data = self.handle_tunnel_data(self.a)
 | 
					 | 
				
			||||||
                self.init_and_report(data)
 | 
					 | 
				
			||||||
                self.show_data()
 | 
					 | 
				
			||||||
                self.stop()
 | 
					 | 
				
			||||||
            except Exception as e:
 | 
					 | 
				
			||||||
                print(f"Error loading tunnel data: {e}")
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        except subprocess.CalledProcessError as e:
 | 
					 | 
				
			||||||
            print(f"Error activating tunnel: {e}", "hier simma")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def init_and_report(self, data=None) -> None:
 | 
					    def init_and_report(self, data=None) -> None:
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Displays the value address, DNS and peer in the labels
 | 
					        Displays the value address, DNS and peer in the labels
 | 
				
			||||||
@@ -881,7 +993,6 @@ class FrameWidgets(ttk.Frame):
 | 
				
			|||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _ = AppConfig.setup_translations()
 | 
					    _ = AppConfig.setup_translations()
 | 
				
			||||||
    tips = LxTools.if_tip(AppConfig.SETTINGS_FILE)
 | 
					 | 
				
			||||||
    LxTools.sigi(AppConfig.TEMP_DIR, AppConfig.USER_FILE)
 | 
					    LxTools.sigi(AppConfig.TEMP_DIR, AppConfig.USER_FILE)
 | 
				
			||||||
    window = Wirepy()
 | 
					    window = Wirepy()
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,12 @@ class AppConfig:
 | 
				
			|||||||
    KEYS_FILE: Path = CONFIG_DIR / "keys"
 | 
					    KEYS_FILE: Path = CONFIG_DIR / "keys"
 | 
				
			||||||
    AUTOSTART_SERVICE: Path = Path.home() / ".config/systemd/user/wg_start.service"
 | 
					    AUTOSTART_SERVICE: Path = Path.home() / ".config/systemd/user/wg_start.service"
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    # Updates
 | 
				
			||||||
 | 
					    # 1 = 1. Year, 09 = Month of the Year, 2924 = Day and Year of the Year
 | 
				
			||||||
 | 
					    VERSION: str = "v. 2.04.1725"
 | 
				
			||||||
 | 
					    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"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Default settings
 | 
					    # Default settings
 | 
				
			||||||
    DEFAULT_SETTINGS: Dict[str, Any] = {
 | 
					    DEFAULT_SETTINGS: Dict[str, Any] = {
 | 
				
			||||||
        "updates": "on",
 | 
					        "updates": "on",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user