2626 from PySide6 .QtGui import QCloseEvent
2727
2828 from aao .core .timing .calibration import FullCalibrationData
29+ from aao .resources .updater import ReleaseInfo
2930
3031_ROOT = os .path .dirname (os .path .dirname (os .path .abspath (__file__ )))
3132if _ROOT not in sys .path :
3233 sys .path .insert (0 , _ROOT )
3334
34- from PySide6 .QtCore import Qt , QThread , QTimer # noqa: E402
35+ from PySide6 .QtCore import QObject , Qt , QThread , QTimer , Signal # noqa: E402
3536from PySide6 .QtWidgets import ( # noqa: E402
3637 QApplication ,
3738 QHBoxLayout ,
@@ -90,6 +91,28 @@ def _key_pressed(vk: int) -> bool:
9091_PAGE_SETTINGS = 3
9192
9293
94+ class _StartupUpdateChecker (QObject ):
95+ """启动时静默检查软件更新(后台线程,不打扰)。
96+
97+ 有新版本则发 update_found(ReleaseInfo);无更新/失败静默(只记日志)。
98+ """
99+
100+ update_found = Signal (object )
101+
102+ def run (self ) -> None :
103+ try :
104+ from aao .resources .updater import UpdateChecker
105+
106+ info = UpdateChecker ().check_software ()
107+ if info is not None and info .has_update :
108+ logger .info ("启动检查:发现新版本 v%s" , info .version )
109+ self .update_found .emit (info )
110+ elif info is not None :
111+ logger .info ("启动检查:已是最新 (v%s)" , info .version )
112+ except Exception : # noqa: BLE001
113+ logger .exception ("启动更新检查失败" )
114+
115+
93116class MainWindow (QMainWindow ):
94117 """主控台:侧栏导航 + QStackedWidget 内容区。"""
95118
@@ -174,6 +197,25 @@ def __init__(
174197 bg .get ("background_image" , "" ), bg .get ("background_opacity" , 25 ) / 100.0
175198 )
176199
200+ # 启动时静默检查软件更新(可关):有新版本则在标题栏挂角标。
201+ self ._latest_version : str | None = None # 启动检查发现的新版本号(无则 None)
202+ self ._startup_check_thread : QThread | None = None
203+ self ._startup_check_worker : _StartupUpdateChecker | None = None
204+ if bg .get ("check_update_on_start" , True ):
205+ self ._startup_check_worker = _StartupUpdateChecker ()
206+ self ._startup_check_thread = QThread ()
207+ self ._startup_check_worker .moveToThread (self ._startup_check_thread )
208+ self ._startup_check_thread .started .connect (self ._startup_check_worker .run )
209+ self ._startup_check_worker .update_found .connect (self ._on_startup_update_found )
210+ self ._startup_check_worker .update_found .connect (self ._startup_check_thread .quit )
211+ self ._startup_check_thread .start ()
212+
213+ def _on_startup_update_found (self , info : ReleaseInfo ) -> None :
214+ """启动检查发现新版本:标题栏挂角标提示(不弹窗,用户自行去设置页更新)。"""
215+ self ._latest_version = info .version
216+ self .setWindowTitle (f"ArknightsAutoOperator [有新版本 v{ info .version } ]" )
217+ logger .info ("标题栏已标记新版本提示,前往设置页「检查更新」一键更新" )
218+
177219 # --- 新手引导 ---
178220
179221 @staticmethod
@@ -543,13 +585,7 @@ def _reset_window_layout(self) -> None:
543585 def _quit_from_tray (self ) -> None :
544586 """托盘「退出」:停所有 worker + 退出应用。"""
545587 self ._force_quit = True
546- self .hotkey_timer .stop ()
547- self .farm_page .stop_and_wait ()
548- if self .worker is not None :
549- self .worker .stop ()
550- if self .worker_thread is not None :
551- self .worker_thread .quit ()
552- self .worker_thread .wait ()
588+ self ._stop_workers ()
553589 self .tray .hide ()
554590 QApplication .quit ()
555591
@@ -566,14 +602,21 @@ def closeEvent(self, event: QCloseEvent) -> None: # noqa: D401
566602 self ._force_quit = True
567603 return
568604 # 真退出(_quit_from_tray 已做清理,或窗口在可见时被强制关闭)
605+ self ._stop_workers ()
606+ super ().closeEvent (event )
607+
608+ def _stop_workers (self ) -> None :
609+ """停所有后台 worker/timer(真退出路径共用)。"""
569610 self .hotkey_timer .stop ()
570611 self .farm_page .stop_and_wait ()
571612 if self .worker is not None :
572613 self .worker .stop ()
573614 if self .worker_thread is not None :
574615 self .worker_thread .quit ()
575616 self .worker_thread .wait ()
576- super ().closeEvent (event )
617+ if self ._startup_check_thread is not None :
618+ self ._startup_check_thread .quit ()
619+ self ._startup_check_thread .wait ()
577620
578621
579622def _ensure_admin () -> None :
0 commit comments