From 2fe4584129ae0b6c9fb322c15ead28f9f659b463 Mon Sep 17 00:00:00 2001 From: KenanZhu <3471685733@qq.com> Date: Fri, 26 Jun 2026 09:16:45 +0800 Subject: [PATCH] =?UTF-8?q?refactor(bulletin):=20=E6=8F=90=E5=8F=96=20ALBu?= =?UTF-8?q?lletinFetchWorker=20=E5=88=B0=E7=8B=AC=E7=AB=8B=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/ALBulletinDialog.py | 49 ++------------ src/gui/ALBulletinPoller.py | 2 +- src/gui/ALBulletinWorker.py | 57 ++++++++++++++++ src/gui/ALSettingsWidget.py | 131 ++++++++++++++++++++---------------- 4 files changed, 134 insertions(+), 105 deletions(-) create mode 100644 src/gui/ALBulletinWorker.py diff --git a/src/gui/ALBulletinDialog.py b/src/gui/ALBulletinDialog.py index ef66430..a670d94 100644 --- a/src/gui/ALBulletinDialog.py +++ b/src/gui/ALBulletinDialog.py @@ -7,14 +7,11 @@ This software is provided "as is", without any warranty of any kind. You may use, modify, and distribute this file under the terms of the MIT License. See the LICENSE file for details. """ -import requests - from datetime import datetime, timedelta from typing import Any from PySide6.QtCore import ( Qt, - QThread, Signal, Slot, QTimer @@ -32,53 +29,12 @@ from PySide6.QtWidgets import ( QWidget ) +from gui.ALBulletinWorker import ALBulletinFetchWorker from gui.ALStatusLabel import ALStatusLabel from gui.resources.ui.Ui_ALBulletinDialog import Ui_ALBulletinDialog from managers.bulletin.BulletinManager import instance as bulletinInstance -class ALBulletinFetchWorker(QThread): - """ - Worker thread for fetching bulletins from the server. - """ - - fetchWorkerIsFinished = Signal(dict) - fetchWorkerFinishedWithError = Signal(str) - - def __init__( - self, - parent=None, - request_url: str = "", - params: dict = None - ): - - super().__init__(parent) - self.__request_url = request_url.rstrip("/") if request_url else "" - self.__params = params or {} - - def run( - self - ): - - try: - response = requests.get( - self.__request_url, params=self.__params, timeout=5 - ) - response.raise_for_status() - r = response.json() - if r.get("code") == 200: - data = r.get("data", {}) - self.fetchWorkerIsFinished.emit(data) - else: - raise Exception( - f"服务器返回错误: [{r.get('code', '未知代码')}] {r.get('msg', '未知错误')}" - ) - except requests.RequestException as e: - self.fetchWorkerFinishedWithError.emit(f"获取公告数据时发生网络错误: \n{e}") - except Exception as e: - self.fetchWorkerFinishedWithError.emit(f"获取公告数据时发生未知错误: \n{e}") - - class ALBulletinItemWidget(QWidget): """ Single bulletin item widget for the bulletin list. @@ -216,6 +172,9 @@ class ALBulletinDialog(QDialog, Ui_ALBulletinDialog): self, iso_str: str ): + """ + Set last sync time to update the UI status. + """ try: dt = datetime.fromisoformat(iso_str) diff --git a/src/gui/ALBulletinPoller.py b/src/gui/ALBulletinPoller.py index 5a328c3..3a3a614 100644 --- a/src/gui/ALBulletinPoller.py +++ b/src/gui/ALBulletinPoller.py @@ -16,7 +16,7 @@ from PySide6.QtCore import ( Slot ) -from gui.ALBulletinDialog import ALBulletinFetchWorker +from gui.ALBulletinWorker import ALBulletinFetchWorker from managers.bulletin.BulletinManager import instance as bulletinInstance diff --git a/src/gui/ALBulletinWorker.py b/src/gui/ALBulletinWorker.py new file mode 100644 index 0000000..0a44dbd --- /dev/null +++ b/src/gui/ALBulletinWorker.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +""" +Copyright (c) 2026 KenanZhu. +All rights reserved. + +This software is provided "as is", without any warranty of any kind. +You may use, modify, and distribute this file under the terms of the MIT License. +See the LICENSE file for details. +""" +import requests + +from PySide6.QtCore import ( + QThread, + Signal +) + + +class ALBulletinFetchWorker(QThread): + """ + Worker thread for fetching bulletins from the server. + """ + + fetchWorkerIsFinished = Signal(dict) + fetchWorkerFinishedWithError = Signal(str) + + def __init__( + self, + parent=None, + request_url: str = "", + params: dict = None + ): + + super().__init__(parent) + self.__request_url = request_url.rstrip("/") if request_url else "" + self.__params = params or {} + + def run( + self + ): + + try: + response = requests.get( + self.__request_url, params=self.__params, timeout=5 + ) + response.raise_for_status() + r = response.json() + if r.get("code") == 200: + data = r.get("data", {}) + self.fetchWorkerIsFinished.emit(data) + else: + raise Exception( + f"服务器返回错误: [{r.get('code', '未知代码')}] {r.get('msg', '未知错误')}" + ) + except requests.RequestException as e: + self.fetchWorkerFinishedWithError.emit(f"获取公告数据时发生网络错误: \n{e}") + except Exception as e: + self.fetchWorkerFinishedWithError.emit(f"获取公告数据时发生未知错误: \n{e}") diff --git a/src/gui/ALSettingsWidget.py b/src/gui/ALSettingsWidget.py index 36eeaa3..16ca582 100644 --- a/src/gui/ALSettingsWidget.py +++ b/src/gui/ALSettingsWidget.py @@ -41,6 +41,7 @@ from managers.theme.ThemeManager import( instance as themeInstance ) +from gui.ALBulletinWorker import ALBulletinFetchWorker from gui.ALWidgetMixin import CenterOnParentMixin from gui.resources.ui.Ui_ALSettingsWidget import Ui_ALSettingsWidget from interfaces.ConfigProvider import ( @@ -196,6 +197,7 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): self ): + # appearance settings theme = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.THEME, "system") style = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.STYLE, "Fusion") custom_theme = self.__cfg_mgr.get(CfgKey.GLOBAL.APPEARANCE.CUSTOM_THEME, "") @@ -218,7 +220,7 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): self.CustomThemeComboBox.setCurrentIndex(idx) self.updateCustomThemeInfo() self.updateCustomThemeStatus() - + # bulletin settings bulletin_mgr = bulletinInstance() self.__original_bulletin_url = bulletin_mgr.serverUrl() self.__original_bulletin_auto_fetch = bulletin_mgr.autoFetch() @@ -274,10 +276,17 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): elif need_theme == "dark": self.DarkThemeRadio.setChecked(True) - def collectSettings( + def clearBulletinTestStatus( self ): + self.BulletinTestStatusLabel.setText("") + self.BulletinTestStatusLabel.setStyleSheet("") + + def collectAppearanceSettings( + self + ) -> tuple[str, str, str]: + if self.LightThemeRadio.isChecked(): theme = "light" elif self.DarkThemeRadio.isChecked(): @@ -290,41 +299,29 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): custom_theme = "" return theme, style, custom_theme - def clearBulletinTestStatus( + def collectBulletinSettings( self - ): - - self.BulletinTestStatusLabel.setText("") - self.BulletinTestStatusLabel.setStyleSheet("") - - def saveBulletinSettings( - self - ): + ) -> tuple[str, bool, int]: url = self.BulletinServerUrlEdit.text().strip() auto_fetch = self.BulletinAutoFetchCheck.isChecked() sync_interval = self.BulletinSyncIntervalSpin.value() if sync_interval < 1: sync_interval = 5 - self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.SERVER_URL, url) - self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.AUTO_FETCH, auto_fetch) - self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.SYNC_INTERVAL, sync_interval) - self.__original_bulletin_url = url - self.__original_bulletin_auto_fetch = auto_fetch - self.__original_bulletin_sync_interval = sync_interval + return url, auto_fetch, sync_interval - def saveAndApply( + def saveAppearanceSettings( self ): - theme, style, custom_theme = self.collectSettings() + theme, style, custom_theme = self.collectAppearanceSettings() self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.STYLE, style) self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.CUSTOM_THEME, custom_theme) setActiveStyle(style) if not _applyCustomTheme(custom_theme, theme): self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.CUSTOM_THEME, "") self.syncRadioFromNeedTheme(custom_theme) - theme, _, _ = self.collectSettings() + theme, _, _ = self.collectAppearanceSettings() self.__cfg_mgr.set(CfgKey.GLOBAL.APPEARANCE.THEME, theme) self.setNavigationIcons() self.updateCustomThemeStatus() @@ -333,7 +330,24 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): self.__original_custom_theme = custom_theme if custom_theme else "" self.__original_style = getActiveStyle() + def saveBulletinSettings( + self + ): + + url, auto_fetch, sync_interval = self.collectBulletinSettings() + self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.SERVER_URL, url) + self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.AUTO_FETCH, auto_fetch) + self.__cfg_mgr.set(CfgKey.GLOBAL.BULLETIN.SYNC_INTERVAL, sync_interval) + self.__original_bulletin_url = url + self.__original_bulletin_auto_fetch = auto_fetch + self.__original_bulletin_sync_interval = sync_interval + + def saveSettings( + self + ): + self.saveBulletinSettings() + self.saveAppearanceSettings() def maybeRestart( self @@ -351,6 +365,34 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): return True return False + @Slot() + def onImportCustomThemeButtonClicked( + self + ): + + file_path, _ = QFileDialog.getOpenFileName( + self, + "导入主题 - AutoLibrary", + "", + "主题文件 (*.altheme *.qss);;所有文件 (*)" + ) + if not file_path: + return + try: + file_id = themeInstance().importTheme(file_path) + self.populateCustomThemes() + idx = self.CustomThemeComboBox.findData(file_id) + if idx >= 0: + self.CustomThemeComboBox.setCurrentIndex(idx) + self.updateCustomThemeStatus() + self.updateCustomThemeInfo() + except Exception as e: + QMessageBox.warning( + self, + "导入失败 - AutoLibrary", + f"无法导入主题文件:{e}" + ) + @Slot() def onRemoveCustomThemeButtonClicked( self @@ -388,34 +430,6 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): f"无法删除主题:{e}" ) - @Slot() - def onImportCustomThemeButtonClicked( - self - ): - - file_path, _ = QFileDialog.getOpenFileName( - self, - "导入主题 - AutoLibrary", - "", - "主题文件 (*.altheme *.qss);;所有文件 (*)" - ) - if not file_path: - return - try: - file_id = themeInstance().importTheme(file_path) - self.populateCustomThemes() - idx = self.CustomThemeComboBox.findData(file_id) - if idx >= 0: - self.CustomThemeComboBox.setCurrentIndex(idx) - self.updateCustomThemeStatus() - self.updateCustomThemeInfo() - except Exception as e: - QMessageBox.warning( - self, - "导入失败 - AutoLibrary", - f"无法导入主题文件:{e}" - ) - @Slot() def onCustomThemeComboBoxChanged( self, @@ -464,30 +478,29 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): self.BulletinTestStatusLabel.setText("正在测试连接...") self.BulletinTestStatusLabel.setStyleSheet("") self.__bulletin_test_t0 = time.monotonic() - from gui.ALBulletinDialog import ALBulletinFetchWorker api_url = url.rstrip("/") + "/bulletins" self.__bulletin_test_worker = ALBulletinFetchWorker( self, api_url, {"date": "", "time": "", "range_hour": "1"} ) self.__bulletin_test_worker.fetchWorkerIsFinished.connect( - self.__onBulletinTestFetched + self.onBulletinTestFetched ) self.__bulletin_test_worker.fetchWorkerFinishedWithError.connect( - self.__onBulletinTestError + self.onBulletinTestError ) self.__bulletin_test_worker.start() @Slot(dict) - def __onBulletinTestFetched( + def onBulletinTestFetched( self, data: dict ): self.__bulletin_test_worker.fetchWorkerIsFinished.disconnect( - self.__onBulletinTestFetched + self.onBulletinTestFetched ) self.__bulletin_test_worker.fetchWorkerFinishedWithError.disconnect( - self.__onBulletinTestError + self.onBulletinTestError ) self.__bulletin_test_worker.deleteLater() self.__bulletin_test_worker = None @@ -500,16 +513,16 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): QTimer.singleShot(3000, self, self.clearBulletinTestStatus) @Slot(str) - def __onBulletinTestError( + def onBulletinTestError( self, error_message: str ): self.__bulletin_test_worker.fetchWorkerIsFinished.disconnect( - self.__onBulletinTestFetched + self.onBulletinTestFetched ) self.__bulletin_test_worker.fetchWorkerFinishedWithError.disconnect( - self.__onBulletinTestError + self.onBulletinTestError ) self.__bulletin_test_worker.deleteLater() self.__bulletin_test_worker = None @@ -529,9 +542,9 @@ class ALSettingsWidget(CenterOnParentMixin, QWidget, Ui_ALSettingsWidget): self ): - _, style, _ = self.collectSettings() + _, style, _ = self.collectAppearanceSettings() style_changed = self.__original_style != style - self.saveAndApply() + self.saveSettings() if style_changed: self.maybeRestart()