2026-07-17 15:27:33 +08:00
|
|
|
|
from .plugin_registry import Event
|
|
|
|
|
|
from PySide6.QtWidgets import QFrame
|
|
|
|
|
|
from PySide6.QtCore import Signal
|
|
|
|
|
|
from .plugins_card_ui import Ui_FramePluginsCard
|
|
|
|
|
|
|
2026-07-20 14:25:18 +08:00
|
|
|
|
|
|
|
|
|
|
def parse_version(version: str) -> tuple:
|
|
|
|
|
|
"""将版本字符串解析为可比较的元组,如 '1.10.0' -> (1, 10, 0)。
|
|
|
|
|
|
|
|
|
|
|
|
非数字段保持原样(字符串与整数混排时按元组规则比较,足够覆盖
|
|
|
|
|
|
常见的 '1.0.0' / '1.10.3' 场景)。None/空值/解析失败返回 (0,),
|
|
|
|
|
|
视为最低版本。
|
|
|
|
|
|
"""
|
|
|
|
|
|
if not version:
|
|
|
|
|
|
return (0,)
|
|
|
|
|
|
try:
|
|
|
|
|
|
parts = []
|
|
|
|
|
|
for seg in str(version).split('.'):
|
|
|
|
|
|
seg = seg.strip()
|
|
|
|
|
|
if seg.isdigit():
|
|
|
|
|
|
parts.append(int(seg))
|
|
|
|
|
|
else:
|
|
|
|
|
|
parts.append(seg)
|
|
|
|
|
|
return tuple(parts) if parts else (0,)
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
return (0,)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-17 15:27:33 +08:00
|
|
|
|
class PluginsCard(QFrame, Ui_FramePluginsCard):
|
2026-07-21 17:04:34 +08:00
|
|
|
|
"""插件卡片组件。
|
2026-07-17 15:27:33 +08:00
|
|
|
|
|
2026-07-21 17:04:34 +08:00
|
|
|
|
继承自 QFrame 和 Ui_FramePluginsCard(Qt Designer 生成的 UI 界面),
|
|
|
|
|
|
负责展示单个插件的图标、名称、版本和描述,并提供安装/更新/卸载按钮。
|
|
|
|
|
|
|
|
|
|
|
|
Attributes:
|
|
|
|
|
|
name: 插件名称
|
|
|
|
|
|
info: 插件元数据字典,含 local version / remote version / description 等
|
2026-07-17 15:27:33 +08:00
|
|
|
|
"""
|
2026-07-21 17:04:34 +08:00
|
|
|
|
|
|
|
|
|
|
# 按钮点击信号,携带事件类型和插件名称
|
|
|
|
|
|
send_event_signal = Signal(Event, str)
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, name: str, info: dict, parent=None) -> None:
|
|
|
|
|
|
"""初始化插件卡片。
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
name: 插件名称
|
|
|
|
|
|
info: 插件元数据字典
|
|
|
|
|
|
parent: 父组件,默认为 None
|
|
|
|
|
|
"""
|
2026-07-17 15:27:33 +08:00
|
|
|
|
super().__init__(parent)
|
|
|
|
|
|
self.setupUi(self)
|
|
|
|
|
|
|
|
|
|
|
|
self.name = name
|
|
|
|
|
|
self.info = info
|
|
|
|
|
|
|
|
|
|
|
|
self.initUI()
|
|
|
|
|
|
|
2026-07-21 17:04:34 +08:00
|
|
|
|
def initUI(self) -> None:
|
|
|
|
|
|
"""初始化卡片 UI:刷新显示内容并绑定按钮事件。"""
|
2026-07-20 13:15:16 +08:00
|
|
|
|
self.refresh()
|
2026-07-20 14:25:18 +08:00
|
|
|
|
self.textBrowser.setReadOnly(True)
|
|
|
|
|
|
self.pushButtonUpdate.clicked.connect(self.on_update_event)
|
2026-07-20 10:31:10 +08:00
|
|
|
|
self.pushButtonInstall.clicked.connect(self.on_install_event)
|
|
|
|
|
|
self.pushButtonUninstall.clicked.connect(self.on_uninstall_event)
|
2026-07-17 15:27:33 +08:00
|
|
|
|
|
2026-07-20 13:15:16 +08:00
|
|
|
|
def refresh(self) -> None:
|
|
|
|
|
|
"""根据 info 刷新卡片显示与按钮状态。"""
|
|
|
|
|
|
self.textBrowser.setMarkdown(self.to_card())
|
2026-07-21 16:26:08 +08:00
|
|
|
|
installed = self.info.get("local version") is not None
|
2026-07-20 13:15:16 +08:00
|
|
|
|
self.pushButtonInstall.setEnabled(not installed)
|
|
|
|
|
|
self.pushButtonUninstall.setEnabled(installed)
|
|
|
|
|
|
if installed:
|
2026-07-20 14:25:18 +08:00
|
|
|
|
remote = parse_version(self.info.get('remote version'))
|
|
|
|
|
|
local = parse_version(self.info.get('local version'))
|
|
|
|
|
|
self.pushButtonUpdate.setEnabled(remote > local)
|
2026-07-20 13:15:16 +08:00
|
|
|
|
else:
|
|
|
|
|
|
self.pushButtonUpdate.setEnabled(False)
|
|
|
|
|
|
|
2026-07-21 17:04:34 +08:00
|
|
|
|
def to_card(self) -> str:
|
|
|
|
|
|
"""将插件信息渲染为 Markdown 卡片文本。
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
格式化的 Markdown 字符串,包含名称、版本和描述。
|
|
|
|
|
|
"""
|
2026-07-21 16:26:08 +08:00
|
|
|
|
remote_ver = self.info.get('remote version')
|
|
|
|
|
|
local_ver = self.info.get('local version')
|
|
|
|
|
|
desc = self.info.get('remote description') or self.info.get('local description') or '暂无'
|
|
|
|
|
|
|
2026-07-17 15:27:33 +08:00
|
|
|
|
card = f"# {self.name}\n\n"
|
2026-07-21 16:26:08 +08:00
|
|
|
|
card += f"**最新:** V{remote_ver}\n\n" if remote_ver else f"**最新:** 暂无版本信息\n\n"
|
|
|
|
|
|
if local_ver is None:
|
2026-07-17 15:27:33 +08:00
|
|
|
|
card += f"**当前:** 未安装!\n\n"
|
|
|
|
|
|
else:
|
2026-07-21 16:26:08 +08:00
|
|
|
|
card += f"**当前:** V{local_ver}\n\n"
|
|
|
|
|
|
card += f"**描述:** {desc}"
|
2026-07-17 15:27:33 +08:00
|
|
|
|
return card
|
|
|
|
|
|
|
2026-07-21 17:04:34 +08:00
|
|
|
|
def on_install_event(self) -> None:
|
|
|
|
|
|
"""触发安装事件。"""
|
2026-07-20 10:31:10 +08:00
|
|
|
|
self.send_event_signal.emit(Event.Install, self.name)
|
|
|
|
|
|
|
2026-07-21 17:04:34 +08:00
|
|
|
|
def on_uninstall_event(self) -> None:
|
|
|
|
|
|
"""触发卸载事件。"""
|
2026-07-20 10:31:10 +08:00
|
|
|
|
self.send_event_signal.emit(Event.Uninstall, self.name)
|
2026-07-21 17:04:34 +08:00
|
|
|
|
|
|
|
|
|
|
def on_update_event(self) -> None:
|
|
|
|
|
|
"""触发更新事件。"""
|
2026-07-20 14:25:18 +08:00
|
|
|
|
self.send_event_signal.emit(Event.Update, self.name)
|