Refactor: Update MenuBar for new GiteaUpdater and flexible tooltips

- Updated MenuBar to use the new GiteaUpdater class for update checks.
- Modified __init__ to accept gitea_api_url and a dictionary of tooltips,
  making the MenuBar more project-independent and translatable.
- Refactored check_for_updates and update_ui_for_update to handle the
  new GiteaUpdater's return values (new version string or None) and
  new states (DISABLED, ERROR).
- Improved updater logic to prevent execution when no updates are available
  or an error occurred.
- Corrected about dialog icon parameter.
This commit is contained in:
2025-08-13 17:18:28 +02:00
parent 8b4068fdc7
commit 6fe090e9e5

View File

@@ -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()