feat: add manual update triggers to settings and tray menu (#1213)

This commit is contained in:
Konukhov Yaroslav
2026-09-04 17:13:56 +03:00
committed by GitHub
parent bd4f3d080c
commit d36bb7df71
4 changed files with 80 additions and 27 deletions
+22
View File
@@ -373,6 +373,7 @@ def install_tray_config_form(
show_autostart: bool = False,
autostart_value: bool = False,
on_language_change: Optional[Callable[[], None]] = None,
on_update_click: Optional[Callable[[], None]] = None,
) -> TrayConfigFormWidgets:
lang_cfg = cfg.get("language", default_config["language"])
set_language(lang_cfg)
@@ -776,6 +777,27 @@ def install_tray_config_form(
justify="left", wraplength=_INNER_W).pack(anchor="w", pady=(0, 8))
rel_url = (st.get("html_url") or "").strip() or RELEASES_PAGE_URL
if st.get("has_update") and on_update_click is not None:
upd_btn_row = ctk.CTkFrame(upd_inner, fg_color="transparent")
upd_btn_row.pack(fill="x")
upd_btn_row.grid_columnconfigure(0, weight=1)
upd_btn_row.grid_columnconfigure(1, weight=1)
ctk.CTkButton(
upd_btn_row, text=t("button.open_release"), height=32,
font=(theme.ui_font_family, 13), corner_radius=8,
fg_color=theme.field_bg, hover_color=theme.field_border,
text_color=theme.text_primary, border_width=1,
border_color=theme.field_border,
command=lambda u=rel_url: webbrowser.open(u),
).grid(row=0, column=0, sticky="ew", padx=(0, 4))
ctk.CTkButton(
upd_btn_row, text=t("button.update"), height=32,
font=(theme.ui_font_family, 13, "bold"), corner_radius=8,
fg_color=theme.tg_blue, hover_color=theme.tg_blue_hover,
text_color="#ffffff",
command=on_update_click,
).grid(row=0, column=1, sticky="ew", padx=(4, 0))
else:
ctk.CTkButton(
upd_inner, text=t("button.open_release"), height=32,
font=(theme.ui_font_family, 13), corner_radius=8,
+1
View File
@@ -113,6 +113,7 @@
"tray.restart": "Restart proxy",
"tray.settings": "Settings...",
"tray.logs": "Open logs",
"tray.update": "Update ({current} → {new})",
"tray.exit": "Exit",
"dialog.restart_title": "Restart?",
+1
View File
@@ -113,6 +113,7 @@
"tray.restart": "Перезапустить прокси",
"tray.settings": "Настройки...",
"tray.logs": "Открыть логи",
"tray.update": "Обновить ({current} → {new})",
"tray.exit": "Выход",
"dialog.restart_title": "Перезапустить?",
+48 -19
View File
@@ -34,7 +34,7 @@ try:
except ImportError:
Image = None
from proxy import get_link_host
from proxy import __version__, get_link_host
from utils.win32_theme import (
is_windows_dark_theme,
@@ -317,6 +317,34 @@ def _perform_update(download_url: str, set_status=None) -> None:
os._exit(0)
def _trigger_update_flow(icon=None, item=None) -> None:
"""Show the update dialog for an update already known to be available.
Reused by the tray "Update" item and the settings dialog's "Update"
button, so an update can still be started after the initial startup
prompt was skipped/closed.
"""
from utils.update_check import RELEASES_PAGE_URL, get_status, get_update_asset
st = get_status()
if not st.get("has_update"):
return
url = (st.get("html_url") or "").strip() or RELEASES_PAGE_URL
ver = st.get("latest") or "?"
asset = get_update_asset(Path(sys.executable), __version__) if IS_FROZEN else None
def _show() -> None:
choice = update_ctk_form(
t("update.available", version=ver),
download_url=asset[0] if asset else None,
release_url=url,
)
if choice == "open":
webbrowser.open(url)
threading.Thread(target=_show, daemon=True, name="manual-update").start()
def _maybe_do_update(cfg: dict, is_exiting) -> None:
if not cfg.get("check_updates", True):
return
@@ -326,23 +354,14 @@ def _maybe_do_update(cfg: dict, is_exiting) -> None:
if is_exiting():
return
try:
from proxy import __version__
from utils.update_check import RELEASES_PAGE_URL, get_status, get_update_asset, run_check
from utils.update_check import run_check
run_check(__version__)
st = get_status()
if not st.get("has_update") or is_exiting():
if _tray_icon is not None:
_tray_icon.menu = _build_menu()
if is_exiting():
return
url = (st.get("html_url") or "").strip() or RELEASES_PAGE_URL
ver = st.get("latest") or "?"
asset = get_update_asset(Path(sys.executable), __version__) if IS_FROZEN else None
choice = update_ctk_form(
t("update.available", version=ver),
download_url=asset[0] if asset else None,
release_url=url,
)
if choice == "open":
webbrowser.open(url)
_trigger_update_flow()
except Exception as exc:
log.warning("Update check failed: %s", repr(exc))
@@ -498,6 +517,7 @@ def _edit_config_dialog() -> None:
show_autostart=_supports_autostart(),
autostart_value=cfg.get("autostart", False),
on_language_change=_refresh_tray_menu,
on_update_click=_trigger_update_flow,
)
_original_appearance = ctk.get_appearance_mode()
@@ -602,16 +622,25 @@ def _build_menu():
host = _config.get("host", DEFAULT_CONFIG["host"])
port = _config.get("port", DEFAULT_CONFIG["port"])
link_host = get_link_host(host)
return pystray.Menu(
items = [
pystray.MenuItem(t("tray.open_telegram", host=link_host, port=port), _on_open_in_telegram, default=True),
pystray.MenuItem(t("tray.copy_link"), _on_copy_link),
pystray.Menu.SEPARATOR,
pystray.MenuItem(t("tray.restart"), _on_restart),
pystray.MenuItem(t("tray.settings"), _on_edit_config),
pystray.MenuItem(t("tray.logs"), _on_open_logs),
pystray.Menu.SEPARATOR,
pystray.MenuItem(t("tray.exit"), _on_exit),
)
]
from utils.update_check import get_status
st = get_status()
if st.get("has_update"):
items.append(pystray.Menu.SEPARATOR)
items.append(pystray.MenuItem(
t("tray.update", current=__version__, new=st.get("latest") or "?"),
_trigger_update_flow,
))
items.append(pystray.Menu.SEPARATOR)
items.append(pystray.MenuItem(t("tray.exit"), _on_exit))
return pystray.Menu(*items)
# entry point