2026-08-06 12:01:38 +08:00
|
|
|
|
"""设置页的界面结构。
|
|
|
|
|
|
|
|
|
|
|
|
分四组:Admin、Android 设备、自动化、安全与诊断。
|
|
|
|
|
|
完整规范见 `docs/client/05-ui-specification.md` §8。
|
|
|
|
|
|
|
|
|
|
|
|
改动本文件前必读 `client/AGENTS.md`。以下几条最容易踩:
|
|
|
|
|
|
|
|
|
|
|
|
- **认证状态只显示“已配置/未配置”或掩码值,绝不回显完整 token。**
|
|
|
|
|
|
- 本文件只负责显示和输入转发,“测试连接”这类会联网、会连手机的动作
|
|
|
|
|
|
放 `settings_ui_event.py`,且必须走后台线程。
|
|
|
|
|
|
- 表单必须有**可见标签**,占位符不能当标签用(占位符一输入就没了,
|
|
|
|
|
|
用户会忘记这个框是干嘛的)。
|
|
|
|
|
|
- 用可滚动布局和 Fluent 设置卡片;MVP 采用显式“保存设置”按钮,
|
|
|
|
|
|
不要在同一页混用即时保存。
|
|
|
|
|
|
- 校验失败时保留用户已输入的内容,并把焦点移到第一个出错的字段,
|
|
|
|
|
|
不要清空重来。
|
|
|
|
|
|
- 图标用 `FluentIcon`,**不得用表情符号**。
|
|
|
|
|
|
- 页面 `objectName` 固定为 `settingsPage`,不要改。
|
|
|
|
|
|
|
|
|
|
|
|
注意:设备连接**不是**独立的顶级页面,统一放在本页,
|
|
|
|
|
|
见 `docs/client/01-requirements.md` §3。
|
|
|
|
|
|
"""
|
2026-08-06 12:06:16 +08:00
|
|
|
|
|
|
|
|
|
|
from PyQt5.QtWidgets import QHBoxLayout, QSizePolicy, QVBoxLayout, QWidget
|
|
|
|
|
|
from qfluentwidgets import (
|
|
|
|
|
|
CaptionLabel,
|
|
|
|
|
|
CardWidget,
|
|
|
|
|
|
FluentIcon as FIF,
|
|
|
|
|
|
LineEdit,
|
|
|
|
|
|
PushButton,
|
|
|
|
|
|
SubtitleLabel,
|
|
|
|
|
|
TitleLabel,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DevicePage(QWidget):
|
|
|
|
|
|
"""Android 设备连接页。"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
|
super().__init__(parent)
|
|
|
|
|
|
self.setObjectName("devicePage")
|
|
|
|
|
|
|
|
|
|
|
|
self.addressInput = LineEdit(self)
|
|
|
|
|
|
self.addressInput.setText("192.168.0.173:5555")
|
|
|
|
|
|
self.addressInput.setPlaceholderText("IP:端口")
|
|
|
|
|
|
self.addressInput.setClearButtonEnabled(True)
|
|
|
|
|
|
self.addressInput.setAccessibleName("Android 设备地址")
|
|
|
|
|
|
|
|
|
|
|
|
self.connectButton = PushButton(FIF.LINK, "连接设备", self)
|
|
|
|
|
|
self.connectButton.setAccessibleName("连接 Android 设备")
|
|
|
|
|
|
self.deviceStatusLabel = CaptionLabel("当前状态:未连接", self)
|
|
|
|
|
|
|
|
|
|
|
|
card = CardWidget(self)
|
|
|
|
|
|
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
|
|
|
|
cardLayout = QVBoxLayout(card)
|
|
|
|
|
|
cardLayout.setContentsMargins(24, 20, 24, 22)
|
|
|
|
|
|
cardLayout.setSpacing(12)
|
|
|
|
|
|
cardLayout.addWidget(SubtitleLabel("无线调试设备", card))
|
|
|
|
|
|
cardLayout.addWidget(CaptionLabel("设备地址", card))
|
|
|
|
|
|
|
|
|
|
|
|
connectionLayout = QHBoxLayout()
|
|
|
|
|
|
connectionLayout.setSpacing(12)
|
|
|
|
|
|
connectionLayout.addWidget(self.addressInput, 1)
|
|
|
|
|
|
connectionLayout.addWidget(self.connectButton)
|
|
|
|
|
|
cardLayout.addLayout(connectionLayout)
|
|
|
|
|
|
cardLayout.addWidget(self.deviceStatusLabel)
|
|
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
|
|
layout.setContentsMargins(36, 30, 36, 36)
|
|
|
|
|
|
layout.setSpacing(16)
|
|
|
|
|
|
layout.addWidget(TitleLabel("设备管理", self))
|
|
|
|
|
|
# description = BodyLabel("管理 uiautomator2 使用的 Android 设备连接。", self)
|
|
|
|
|
|
# description.setWordWrap(True)
|
|
|
|
|
|
# layout.addWidget(description)
|
|
|
|
|
|
layout.addWidget(card)
|
|
|
|
|
|
layout.addStretch(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SettingsPage(QWidget):
|
|
|
|
|
|
"""后续设置项的扩展入口。"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
|
super().__init__(parent)
|
|
|
|
|
|
self.setObjectName("settingsPage")
|
|
|
|
|
|
|
|
|
|
|
|
card = CardWidget(self)
|
|
|
|
|
|
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
|
|
|
|
cardLayout = QVBoxLayout(card)
|
|
|
|
|
|
cardLayout.setContentsMargins(24, 20, 24, 22)
|
|
|
|
|
|
cardLayout.setSpacing(8)
|
|
|
|
|
|
cardLayout.addWidget(SubtitleLabel("应用设置", card))
|
|
|
|
|
|
# hint = BodyLabel("主题、日志和任务策略可以在这里继续扩展。", card)
|
|
|
|
|
|
# hint.setWordWrap(True)
|
|
|
|
|
|
# cardLayout.addWidget(hint)
|
|
|
|
|
|
|
|
|
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
|
|
layout.setContentsMargins(36, 30, 36, 36)
|
|
|
|
|
|
layout.setSpacing(16)
|
|
|
|
|
|
layout.addWidget(TitleLabel("设置", self))
|
|
|
|
|
|
layout.addWidget(card)
|
|
|
|
|
|
layout.addStretch(1)
|