301 lines
12 KiB
Python
301 lines
12 KiB
Python
|
|
# coding: utf-8
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
import requests
|
|||
|
|
from PyQt6.QtCore import Qt, QThread, pyqtSignal
|
|||
|
|
from PyQt6.QtWidgets import (
|
|||
|
|
QLabel,
|
|||
|
|
QMessageBox,
|
|||
|
|
QSizePolicy,
|
|||
|
|
QSpacerItem,
|
|||
|
|
QVBoxLayout,
|
|||
|
|
QWidget,
|
|||
|
|
)
|
|||
|
|
from qfluentwidgets import (ComboBoxSettingCard, FluentIcon, ImageLabel, MessageBox, PrimaryPushSettingCard,
|
|||
|
|
SettingCardGroup, SwitchSettingCard)
|
|||
|
|
|
|||
|
|
from app.core import cfg, lang, qconfig, signalBus
|
|||
|
|
from app.core.utils.version import version
|
|||
|
|
|
|||
|
|
|
|||
|
|
class AppInfoInterface(QWidget):
|
|||
|
|
"""
|
|||
|
|
APP信息页面
|
|||
|
|
包含语言切换功能
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self, parent=None):
|
|||
|
|
super().__init__(parent)
|
|||
|
|
self.setObjectName("appInfoInterface")
|
|||
|
|
self.initUI()
|
|||
|
|
self.connectSignalToSlot()
|
|||
|
|
# 移除初始化时的自动检查,改为由登录成功信号触发
|
|||
|
|
|
|||
|
|
def initUI(self):
|
|||
|
|
# 创建主布局
|
|||
|
|
mainLayout = QVBoxLayout(self)
|
|||
|
|
mainLayout.setContentsMargins(30, 30, 30, 30)
|
|||
|
|
mainLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
|||
|
|
|
|||
|
|
self.titleImageLabel = ImageLabel(":app/images/title.jpg", self)
|
|||
|
|
self.titleImageLabel.scaledToHeight(130)
|
|||
|
|
mainLayout.addWidget(self.titleImageLabel, 0, Qt.AlignmentFlag.AlignHCenter)
|
|||
|
|
|
|||
|
|
# 添加标题
|
|||
|
|
self.titleLabel = QLabel(lang("应用信息"))
|
|||
|
|
self.titleLabel.setStyleSheet("QLabel { font-size: 24px; font-weight: bold; }")
|
|||
|
|
mainLayout.addWidget(self.titleLabel)
|
|||
|
|
|
|||
|
|
# 创建设置卡组
|
|||
|
|
self.languageGroup = SettingCardGroup(lang("语言设置"), self)
|
|||
|
|
|
|||
|
|
# 语言选择设置卡
|
|||
|
|
self.languageCard = ComboBoxSettingCard(
|
|||
|
|
title=lang("语言设置"),
|
|||
|
|
icon=FluentIcon.LANGUAGE,
|
|||
|
|
texts=["中文", "English"],
|
|||
|
|
configItem=cfg.language,
|
|||
|
|
parent=self.languageGroup,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 将设置卡添加到组
|
|||
|
|
self.languageGroup.addSettingCard(self.languageCard)
|
|||
|
|
|
|||
|
|
# 将设置卡组添加到主布局
|
|||
|
|
mainLayout.addWidget(self.languageGroup)
|
|||
|
|
|
|||
|
|
# 创建更新设置卡组
|
|||
|
|
self.updateGroup = SettingCardGroup(lang("更新设置"), self)
|
|||
|
|
|
|||
|
|
# 自动更新设置开关
|
|||
|
|
self.autoUpdateSwitch = SwitchSettingCard(
|
|||
|
|
title=lang("开启自动更新"),
|
|||
|
|
icon=FluentIcon.UPDATE,
|
|||
|
|
configItem=cfg.checkUpdateAtStartUp,
|
|||
|
|
parent=self.updateGroup,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 手动检查更新设置卡
|
|||
|
|
self.checkUpdateCard = PrimaryPushSettingCard(
|
|||
|
|
title=lang("检查更新"),
|
|||
|
|
text=lang("检查是否有新版本可用"),
|
|||
|
|
icon=FluentIcon.UPDATE,
|
|||
|
|
parent=self.updateGroup,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 当前版本信息
|
|||
|
|
self.versionLabel = QLabel(f"{lang('当前版本')}: {version}")
|
|||
|
|
self.versionLabel.setStyleSheet(
|
|||
|
|
"QLabel { font-size: 14px; color: #666; margin-top: 10px; margin-left: 10px; }"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 将设置卡添加到组
|
|||
|
|
self.updateGroup.addSettingCard(self.autoUpdateSwitch)
|
|||
|
|
self.updateGroup.addSettingCard(self.checkUpdateCard)
|
|||
|
|
self.updateGroup.layout().addWidget(self.versionLabel)
|
|||
|
|
|
|||
|
|
# 将更新设置卡组添加到主布局
|
|||
|
|
mainLayout.addWidget(self.updateGroup)
|
|||
|
|
|
|||
|
|
# 添加空白占位符
|
|||
|
|
spacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|||
|
|
mainLayout.addItem(spacer)
|
|||
|
|
|
|||
|
|
# 底部空间
|
|||
|
|
bottomSpacer = QSpacerItem(20, 100, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
|||
|
|
mainLayout.addItem(bottomSpacer)
|
|||
|
|
|
|||
|
|
def connectSignalToSlot(self):
|
|||
|
|
# 连接语言变更信号
|
|||
|
|
signalBus.languageChanged.connect(self.updateUI)
|
|||
|
|
# 连接ComboBox的当前文本变更信号
|
|||
|
|
self.languageCard.comboBox.currentTextChanged.connect(self.onLanguageChanged)
|
|||
|
|
# 连接检查更新按钮信号
|
|||
|
|
self.checkUpdateCard.clicked.connect(self.manualCheckUpdate)
|
|||
|
|
# 自动更新开关的信号已通过configItem自动连接,无需额外处理
|
|||
|
|
# 连接登录成功信号,在用户登录后执行自动检查更新
|
|||
|
|
signalBus.loginSuccessSignal.connect(self.onLoginSuccess)
|
|||
|
|
|
|||
|
|
def checkUpdate(self):
|
|||
|
|
"""检查应用更新"""
|
|||
|
|
try:
|
|||
|
|
# 发送请求获取应用信息
|
|||
|
|
url = "https://leon.miaostars.com/api.php?t=getappinfo&id=23"
|
|||
|
|
response = requests.get(url, timeout=10)
|
|||
|
|
response.raise_for_status()
|
|||
|
|
|
|||
|
|
# 解析JSON响应
|
|||
|
|
data = response.json()
|
|||
|
|
|
|||
|
|
if data.get("status") == "success":
|
|||
|
|
app_data = data.get("data", {})
|
|||
|
|
versions = app_data.get("versions", [])
|
|||
|
|
|
|||
|
|
if versions:
|
|||
|
|
# 获取最新版本
|
|||
|
|
latest_version = versions[0].get("version", "")
|
|||
|
|
|
|||
|
|
# 比较版本号 - 只要版本不同就提示更新
|
|||
|
|
if latest_version and latest_version != version:
|
|||
|
|
# 有新版本
|
|||
|
|
changelog = versions[0].get("changelog", "")
|
|||
|
|
api_file_path = versions[0].get("file_path", "")
|
|||
|
|
# 确保使用完整的URL,如果路径不包含协议,则添加域名前缀
|
|||
|
|
if api_file_path:
|
|||
|
|
# 检查是否是完整的URL
|
|||
|
|
if not (
|
|||
|
|
api_file_path.startswith("http://")
|
|||
|
|
or api_file_path.startswith("https://")
|
|||
|
|
):
|
|||
|
|
# 添加域名前缀,确保链接完整
|
|||
|
|
file_path = (
|
|||
|
|
f"https://leon.miaostars.com/{api_file_path}"
|
|||
|
|
)
|
|||
|
|
else:
|
|||
|
|
file_path = api_file_path
|
|||
|
|
else:
|
|||
|
|
# 使用默认下载链接
|
|||
|
|
file_path = "https://leon.miaostars.com/app.php?id=23"
|
|||
|
|
|
|||
|
|
# 使用QFluentWidgets的MessageBox提示用户更新
|
|||
|
|
msg_box = MessageBox(
|
|||
|
|
lang("发现新版本"),
|
|||
|
|
f"{lang('当前版本')}: {version}\n{lang('最新版本')}: {latest_version}\n\n{lang('更新内容')}:\n{changelog}",
|
|||
|
|
self,
|
|||
|
|
)
|
|||
|
|
msg_box.yesButton.setText(lang("立即更新"))
|
|||
|
|
msg_box.cancelButton.setText(lang("稍后更新"))
|
|||
|
|
|
|||
|
|
# QFluentWidgets的MessageBox.exec()返回True表示用户点击了确认按钮
|
|||
|
|
if msg_box.exec():
|
|||
|
|
# 添加下载更新的逻辑
|
|||
|
|
# 例如:打开浏览器访问下载链接
|
|||
|
|
if file_path:
|
|||
|
|
import webbrowser
|
|||
|
|
|
|||
|
|
webbrowser.open(file_path)
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
# 没有新版本或请求失败
|
|||
|
|
return False
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"检查更新失败: {e}")
|
|||
|
|
# 如果是手动检查更新,则显示错误提示
|
|||
|
|
if hasattr(self, "is_manual_check") and self.is_manual_check:
|
|||
|
|
error_box = MessageBox(
|
|||
|
|
lang("检查更新失败"),
|
|||
|
|
f"{lang('无法连接到更新服务器,请稍后再试。')}\n{str(e)}",
|
|||
|
|
self,
|
|||
|
|
)
|
|||
|
|
error_box.cancelButton.setVisible(False)
|
|||
|
|
error_box.exec()
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def manualCheckUpdate(self):
|
|||
|
|
"""手动检查更新"""
|
|||
|
|
self.is_manual_check = True
|
|||
|
|
has_update = self.checkUpdate()
|
|||
|
|
if not has_update and self.is_manual_check:
|
|||
|
|
# 如果是手动检查且没有更新
|
|||
|
|
no_update_box = MessageBox(
|
|||
|
|
lang("已是最新版本"),
|
|||
|
|
f"{lang('当前版本')} {version} {lang('已是最新版本。')}",
|
|||
|
|
self,
|
|||
|
|
)
|
|||
|
|
no_update_box.cancelButton.setVisible(False)
|
|||
|
|
no_update_box.exec()
|
|||
|
|
self.is_manual_check = False
|
|||
|
|
|
|||
|
|
def autoCheckUpdate(self):
|
|||
|
|
"""自动检查更新"""
|
|||
|
|
print(f"自动检查更新已触发,配置状态: {cfg.checkUpdateAtStartUp.value}")
|
|||
|
|
|
|||
|
|
# 在单独的线程中执行,避免阻塞UI
|
|||
|
|
class UpdateCheckThread(QThread):
|
|||
|
|
update_available = pyqtSignal(bool)
|
|||
|
|
|
|||
|
|
def run(self):
|
|||
|
|
try:
|
|||
|
|
print("开始检查更新...")
|
|||
|
|
url = "https://leon.miaostars.com/api.php?t=getappinfo&id=23"
|
|||
|
|
response = requests.get(url, timeout=10)
|
|||
|
|
response.raise_for_status()
|
|||
|
|
data = response.json()
|
|||
|
|
|
|||
|
|
if data.get("status") == "success":
|
|||
|
|
app_data = data.get("data", {})
|
|||
|
|
versions = app_data.get("versions", [])
|
|||
|
|
|
|||
|
|
if versions:
|
|||
|
|
latest_version = versions[0].get("version", "")
|
|||
|
|
print(f"当前版本: {version}, 最新版本: {latest_version}")
|
|||
|
|
if latest_version and latest_version != version:
|
|||
|
|
print("发现新版本,准备显示更新提示")
|
|||
|
|
self.update_available.emit(True)
|
|||
|
|
return
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"自动检查更新出错: {e}")
|
|||
|
|
|
|||
|
|
self.update_available.emit(False)
|
|||
|
|
|
|||
|
|
# 创建并启动线程
|
|||
|
|
self.update_thread = UpdateCheckThread()
|
|||
|
|
self.update_thread.update_available.connect(self.onAutoUpdateAvailable)
|
|||
|
|
self.update_thread.start()
|
|||
|
|
|
|||
|
|
def onAutoUpdateAvailable(self, available):
|
|||
|
|
"""自动检查更新结果处理"""
|
|||
|
|
print(f"自动检查更新结果: {'有更新' if available else '无更新'}")
|
|||
|
|
if available:
|
|||
|
|
# 自动检查到更新时,再次调用checkUpdate显示提示
|
|||
|
|
self.is_manual_check = False
|
|||
|
|
self.checkUpdate()
|
|||
|
|
|
|||
|
|
def onLoginSuccess(self):
|
|||
|
|
"""用户登录成功后的处理"""
|
|||
|
|
print(f"用户登录成功,检查是否开启自动更新: {cfg.checkUpdateAtStartUp.value}")
|
|||
|
|
# 在用户登录成功后,根据配置决定是否自动检查更新
|
|||
|
|
if cfg.checkUpdateAtStartUp.value:
|
|||
|
|
self.autoCheckUpdate()
|
|||
|
|
|
|||
|
|
def onLanguageChanged(self, text):
|
|||
|
|
# 语言变更处理
|
|||
|
|
# 从选项映射获取对应的语言代码
|
|||
|
|
lang_map = {"中文": "zh", "English": "en"}
|
|||
|
|
lang_code = lang_map.get(text, "zh")
|
|||
|
|
|
|||
|
|
# 保存到配置
|
|||
|
|
qconfig.set(cfg.language, lang_code)
|
|||
|
|
|
|||
|
|
# 显示重启提示
|
|||
|
|
reply = QMessageBox.question(
|
|||
|
|
self,
|
|||
|
|
lang("语言变更"),
|
|||
|
|
lang("语言已变更,是否立即重启应用以应用新语言?"),
|
|||
|
|
QMessageBox.Yes | QMessageBox.No,
|
|||
|
|
QMessageBox.Yes,
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if reply == QMessageBox.Yes:
|
|||
|
|
# 重启应用
|
|||
|
|
self.restartApplication()
|
|||
|
|
|
|||
|
|
def updateUI(self):
|
|||
|
|
# 更新UI文本
|
|||
|
|
self.titleLabel.setText(lang("应用信息"))
|
|||
|
|
self.hintLabel.setText(lang("此页面正在建设中..."))
|
|||
|
|
# 注意:SettingCardGroup可能没有setTitle方法,需要根据实际API调整
|
|||
|
|
|
|||
|
|
def restartApplication(self):
|
|||
|
|
"""重启应用程序"""
|
|||
|
|
# 保存配置
|
|||
|
|
qconfig.save()
|
|||
|
|
# 获取当前Python解释器路径和脚本路径
|
|||
|
|
python = sys.executable
|
|||
|
|
script = os.path.abspath(sys.argv[0])
|
|||
|
|
# 退出当前进程
|
|||
|
|
sys.exit()
|
|||
|
|
# 注意:在实际应用中,这里应该使用subprocess重新启动应用,但为了安全考虑,
|
|||
|
|
# 这里仅退出当前进程,让用户手动重启
|