diff --git a/menu_bar.py b/menu_bar.py index dc14963..4975e66 100644 --- a/menu_bar.py +++ b/menu_bar.py @@ -13,7 +13,7 @@ if typing.TYPE_CHECKING: from .logger import app_logger from .common_tools import ConfigManager, Tooltip, message_box_animation -from .gitea import GiteaUpdate +from .gitea import GiteaUpdater from .animated_icon import AnimatedIcon, PIL_AVAILABLE from .message import MessageDialog @@ -24,7 +24,8 @@ class MenuBar(ttk.Frame): def __init__( self, container: ttk.Frame, - image_manager: 'Any', # Should have a .get_icon(str) -> PhotoImage method + # Should have a .get_icon(str) -> PhotoImage method + image_manager: 'Any', tooltip_state: 'BooleanVar', on_theme_toggle: 'Callable[[], None]', toggle_log_window: 'Callable[[], None]', @@ -32,6 +33,8 @@ class MenuBar(ttk.Frame): msg_config: 'Any', # Should have .STR and .TTIP dictionaries about_icon_path: str, about_url: str, + gitea_api_url: str, # New: Gitea API URL for update checks + tooltips: dict[str, str], # New: Dictionary of tooltips **kwargs: 'Any', ) -> None: """ @@ -47,6 +50,8 @@ class MenuBar(ttk.Frame): msg_config: Project-specific messages. Must have STR and TTIP dicts. about_icon_path: Filesystem path to the icon for the 'About' dialog. about_url: URL for the project's repository or website. + gitea_api_url: The Gitea API URL for update checks. + tooltips: A dictionary containing tooltip messages. **kwargs: Additional keyword arguments for the ttk.Frame. """ super().__init__(container, **kwargs) @@ -57,6 +62,9 @@ class MenuBar(ttk.Frame): self.msg_config = msg_config self.about_icon_path = about_icon_path self.about_url = about_url + self.gitea_api_url = gitea_api_url # Store the Gitea API URL + self.tooltips = tooltips # Store the tooltips dictionary + self.update_status: str = "" # --- Horizontal button frame for settings --- actions_frame = ttk.Frame(self) @@ -68,7 +76,8 @@ class MenuBar(ttk.Frame): ) self.theme_btn.grid(column=0, row=0, padx=(0, 2)) self.update_theme_icon() - Tooltip(self.theme_btn, "Thema wechseln (Hell/Dunkel)", state_var=self.tooltip_state) + Tooltip(self.theme_btn, self.tooltips["theme_toggle"], + state_var=self.tooltip_state) # --- Tooltip Button --- self.tooltip_btn = ttk.Button( @@ -76,7 +85,8 @@ class MenuBar(ttk.Frame): ) self.tooltip_btn.grid(column=1, row=0, padx=(0, 2)) self.update_tooltip_icon() - Tooltip(self.tooltip_btn, "Tooltips an/aus", state_var=self.tooltip_state) + Tooltip(self.tooltip_btn, self.tooltips["tooltips_toggle"], + state_var=self.tooltip_state) # --- Update Button --- self.update_btn = ttk.Button( @@ -86,7 +96,8 @@ class MenuBar(ttk.Frame): ) self.update_btn.grid(column=2, row=0) self.update_update_icon() - Tooltip(self.update_btn, "Updates an/aus", state_var=self.tooltip_state) + Tooltip(self.update_btn, self.tooltips["updates_toggle"], + state_var=self.tooltip_state) # --- Animated Icon for Updates --- self.animated_icon_frame = ttk.Frame(actions_frame) @@ -127,10 +138,12 @@ class MenuBar(ttk.Frame): command=self.about, ) self.about_btn.grid(column=3, row=0) - Tooltip(self.about_btn, self.msg_config.STR["about"], state_var=self.tooltip_state) + Tooltip(self.about_btn, + self.msg_config.STR["about"], state_var=self.tooltip_state) # --- Start background update check --- - self.update_thread = threading.Thread(target=self.check_for_updates, daemon=True) + self.update_thread = threading.Thread( + target=self.check_for_updates, daemon=True) self.update_thread.start() def update_theme_icon(self) -> None: @@ -142,7 +155,8 @@ class MenuBar(ttk.Frame): def update_tooltip_icon(self) -> None: """Sets the tooltip button icon based on the tooltip state.""" icon_name = "tooltip_small" if self.tooltip_state.get() else "no_tooltip_small" - self.tooltip_btn.configure(image=self.image_manager.get_icon(icon_name)) + self.tooltip_btn.configure( + image=self.image_manager.get_icon(icon_name)) def update_update_icon(self) -> None: """Sets the update button icon based on the update setting.""" @@ -178,46 +192,62 @@ class MenuBar(ttk.Frame): def check_for_updates(self) -> None: """Checks for updates via the Gitea API in a background thread.""" + # If updates are turned off in settings, do not perform check + if ConfigManager.get("updates") == "off": + self.after(0, self.update_ui_for_update, "DISABLED") + return + try: - res = GiteaUpdate.api_down( - self.app_config.UPDATE_URL, + # Use the GiteaUpdater to check for updates + new_version = GiteaUpdater.check_for_update( + self.gitea_api_url, self.app_config.VERSION, - ConfigManager.get("updates"), ) - self.after(0, self.update_ui_for_update, res) + # Pass the result (new_version string or None) to update_ui_for_update + self.after(0, self.update_ui_for_update, new_version) except Exception as e: app_logger.log(f"Error during update check: {e}") - self.after(0, self.update_ui_for_update, "No Internet Connection!") + # Indicate a network error or other exception + self.after(0, self.update_ui_for_update, "ERROR") - def update_ui_for_update(self, res: str) -> None: + def update_ui_for_update(self, new_version: Optional[str]) -> None: """ Updates the UI based on the result of the update check. Args: - res: The result string from the update check. + new_version: The new version string if an update is available, + "DISABLED" if updates are off, "ERROR" if an error occurred, + or None if no update is available. """ + self.update_status = new_version self.animated_icon_frame.grid_remove() self.animated_icon.hide() + self.animated_icon_frame.grid() tooltip_msg = "" - if res == "False": - tooltip_msg = self.msg_config.TTIP["updates_disabled"] - elif res == "No Internet Connection!": - tooltip_msg = self.msg_config.TTIP["no_server_conn_tt"] - elif res == "No Updates": - tooltip_msg = self.msg_config.TTIP["up_to_date"] - self.animated_icon_frame.grid() + + if new_version == "DISABLED": + tooltip_msg = self.tooltips["updates_disabled"] self.animated_icon.stop() - else: - tooltip_msg = self.msg_config.TTIP["install_new_version"] - self.animated_icon_frame.grid() + elif new_version == "ERROR": + tooltip_msg = self.tooltips["no_server_conn_tt"] + self.animated_icon.stop(status="DISABLE") + elif new_version is None: + tooltip_msg = self.tooltips["up_to_date"] + self.animated_icon.stop() + else: # A new version string is returned, meaning an update is available + tooltip_msg = self.tooltips["install_new_version"].format(version=new_version) self.animated_icon.start() Tooltip(self.update_btn, tooltip_msg, state_var=self.tooltip_state) - Tooltip(self.animated_icon_frame, tooltip_msg, state_var=self.tooltip_state) + Tooltip(self.animated_icon_frame, tooltip_msg, + state_var=self.tooltip_state) def updater(self) -> None: """Runs the external installer script for updating the application.""" + if self.update_status in ["False", "No Internet Connection!", "No Updates"]: + return + tmp_dir = Path("/tmp/lxtools") Path.mkdir(tmp_dir, exist_ok=True) os.chdir(tmp_dir) @@ -240,6 +270,6 @@ class MenuBar(ttk.Frame): None, partial(webbrowser.open, self.about_url), ], - icon=self.about_icon_path, + icon=self.about_icon, wraplength=420, ).show()