2026-08-06 12:01:38 +08:00
|
|
|
"""设置页的界面结构。
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
本文件只负责显示设备信息和提供界面更新入口。按钮事件统一由
|
|
|
|
|
``settings_ui_event.py`` 绑定;ADB、SQLite 和硬件信息读取不得放在这里。
|
2026-08-06 12:01:38 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
改动本文件前必读 ``client/AGENTS.md``。页面 ``objectName`` 固定为
|
|
|
|
|
``settingsPage``,图标使用 ``FluentIcon``,不得使用表情符号。
|
2026-08-06 12:01:38 +08:00
|
|
|
"""
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
from dataclasses import dataclass
|
|
|
|
|
from typing import Iterable, Optional
|
|
|
|
|
|
2026-08-06 15:50:47 +08:00
|
|
|
from PyQt5.QtCore import QAbstractTableModel, QEvent, QModelIndex, Qt, pyqtSignal
|
2026-08-06 15:31:05 +08:00
|
|
|
from PyQt5.QtWidgets import (
|
|
|
|
|
QAbstractItemView,
|
|
|
|
|
QFormLayout,
|
|
|
|
|
QHeaderView,
|
|
|
|
|
QHBoxLayout,
|
|
|
|
|
QSizePolicy,
|
|
|
|
|
QVBoxLayout,
|
|
|
|
|
QWidget,
|
|
|
|
|
)
|
2026-08-06 12:06:16 +08:00
|
|
|
from qfluentwidgets import (
|
|
|
|
|
CaptionLabel,
|
|
|
|
|
CardWidget,
|
|
|
|
|
FluentIcon as FIF,
|
|
|
|
|
LineEdit,
|
|
|
|
|
PushButton,
|
2026-08-06 15:31:05 +08:00
|
|
|
ScrollArea,
|
2026-08-06 12:06:16 +08:00
|
|
|
SubtitleLabel,
|
2026-08-06 15:31:05 +08:00
|
|
|
TableView,
|
2026-08-06 12:06:16 +08:00
|
|
|
TitleLabel,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
@dataclass(frozen=True)
|
|
|
|
|
class AndroidDeviceRow:
|
|
|
|
|
"""一台 ADB 已发现设备的界面数据。"""
|
|
|
|
|
|
|
|
|
|
serial: str
|
|
|
|
|
connection_type: str
|
|
|
|
|
model: str = "—"
|
|
|
|
|
android_version: str = "—"
|
|
|
|
|
status: str = "device"
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def status_text(self) -> str:
|
|
|
|
|
return {
|
|
|
|
|
"device": "已连接",
|
|
|
|
|
"offline": "离线",
|
|
|
|
|
"unauthorized": "未授权",
|
|
|
|
|
}.get(self.status, self.status or "未知")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class AndroidDeviceTableModel(QAbstractTableModel):
|
|
|
|
|
"""Android 设备表格模型,使用序列号维护互斥勾选。"""
|
|
|
|
|
|
|
|
|
|
checkedDeviceChanged = pyqtSignal(str)
|
|
|
|
|
|
|
|
|
|
HEADERS = ("选择", "设备号", "连接方式", "型号", "Android 版本", "状态")
|
2026-08-06 12:06:16 +08:00
|
|
|
|
|
|
|
|
def __init__(self, parent=None):
|
|
|
|
|
super().__init__(parent)
|
2026-08-06 15:31:05 +08:00
|
|
|
self._rows: list[AndroidDeviceRow] = []
|
|
|
|
|
self._checked_serial = ""
|
2026-08-06 15:50:47 +08:00
|
|
|
self._placeholder_row_count = 1
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def rowCount(self, parent=QModelIndex()) -> int:
|
2026-08-06 15:50:47 +08:00
|
|
|
if parent.isValid():
|
|
|
|
|
return 0
|
|
|
|
|
return len(self._rows) or self._placeholder_row_count
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def columnCount(self, parent=QModelIndex()) -> int:
|
|
|
|
|
return 0 if parent.isValid() else len(self.HEADERS)
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
|
|
|
|
if role == Qt.DisplayRole and orientation == Qt.Horizontal:
|
|
|
|
|
return self.HEADERS[section]
|
|
|
|
|
return super().headerData(section, orientation, role)
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def data(self, index, role=Qt.DisplayRole):
|
|
|
|
|
if not index.isValid() or not 0 <= index.row() < len(self._rows):
|
|
|
|
|
return None
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
device = self._rows[index.row()]
|
|
|
|
|
if index.column() == 0 and role == Qt.CheckStateRole:
|
|
|
|
|
return Qt.Checked if device.serial == self._checked_serial else Qt.Unchecked
|
|
|
|
|
|
|
|
|
|
if role == Qt.DisplayRole:
|
|
|
|
|
values = (
|
|
|
|
|
"",
|
|
|
|
|
device.serial,
|
|
|
|
|
device.connection_type,
|
|
|
|
|
device.model,
|
|
|
|
|
device.android_version,
|
|
|
|
|
device.status_text,
|
|
|
|
|
)
|
|
|
|
|
return values[index.column()]
|
|
|
|
|
|
|
|
|
|
if role == Qt.TextAlignmentRole:
|
|
|
|
|
if index.column() in (0, 2, 4, 5):
|
|
|
|
|
return int(Qt.AlignCenter)
|
|
|
|
|
return int(Qt.AlignLeft | Qt.AlignVCenter)
|
|
|
|
|
|
|
|
|
|
if role == Qt.ToolTipRole:
|
|
|
|
|
if index.column() == 0 and device.status != "device":
|
|
|
|
|
return "设备状态正常后才能选择"
|
|
|
|
|
if index.column() == 1:
|
|
|
|
|
return device.serial
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def flags(self, index):
|
2026-08-06 15:50:47 +08:00
|
|
|
if not index.isValid() or index.row() >= len(self._rows):
|
2026-08-06 15:31:05 +08:00
|
|
|
return Qt.NoItemFlags
|
|
|
|
|
|
|
|
|
|
flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable
|
|
|
|
|
if index.column() == 0 and self._rows[index.row()].status == "device":
|
|
|
|
|
flags |= Qt.ItemIsUserCheckable
|
|
|
|
|
return flags
|
|
|
|
|
|
|
|
|
|
def setData(self, index, value, role=Qt.EditRole) -> bool:
|
|
|
|
|
if (
|
|
|
|
|
not index.isValid()
|
2026-08-06 15:50:47 +08:00
|
|
|
or index.row() >= len(self._rows)
|
2026-08-06 15:31:05 +08:00
|
|
|
or index.column() != 0
|
|
|
|
|
or role != Qt.CheckStateRole
|
|
|
|
|
or self._rows[index.row()].status != "device"
|
|
|
|
|
):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
serial = self._rows[index.row()].serial
|
|
|
|
|
checked_serial = serial if value == Qt.Checked else ""
|
|
|
|
|
self.set_checked_serial(checked_serial)
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def set_devices(self, devices: Iterable[AndroidDeviceRow]) -> None:
|
|
|
|
|
"""替换设备列表,并按稳定序列号保留有效勾选。"""
|
|
|
|
|
|
|
|
|
|
rows = list(devices)
|
|
|
|
|
valid_serials = {row.serial for row in rows if row.status == "device"}
|
|
|
|
|
checked_serial = self._checked_serial
|
|
|
|
|
|
|
|
|
|
self.beginResetModel()
|
|
|
|
|
self._rows = rows
|
|
|
|
|
if checked_serial not in valid_serials:
|
|
|
|
|
self._checked_serial = ""
|
|
|
|
|
self.endResetModel()
|
|
|
|
|
|
|
|
|
|
if checked_serial != self._checked_serial:
|
|
|
|
|
self.checkedDeviceChanged.emit(self._checked_serial)
|
|
|
|
|
|
2026-08-06 15:50:47 +08:00
|
|
|
def set_placeholder_row_count(self, count: int) -> None:
|
|
|
|
|
"""设置空设备列表占位行数,真实设备行不受影响。"""
|
|
|
|
|
|
|
|
|
|
count = max(1, count)
|
|
|
|
|
if self._rows or count == self._placeholder_row_count:
|
|
|
|
|
self._placeholder_row_count = count
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
self.beginResetModel()
|
|
|
|
|
self._placeholder_row_count = count
|
|
|
|
|
self.endResetModel()
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def set_checked_serial(self, serial: str) -> None:
|
|
|
|
|
"""勾选一台正常设备;传空字符串清除勾选。"""
|
|
|
|
|
|
|
|
|
|
if serial:
|
|
|
|
|
selectable = any(
|
|
|
|
|
row.serial == serial and row.status == "device" for row in self._rows
|
|
|
|
|
)
|
|
|
|
|
if not selectable:
|
|
|
|
|
serial = ""
|
|
|
|
|
|
|
|
|
|
if serial == self._checked_serial:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
old_serial = self._checked_serial
|
|
|
|
|
self._checked_serial = serial
|
|
|
|
|
for candidate in (old_serial, serial):
|
|
|
|
|
row = self.row_for_serial(candidate)
|
|
|
|
|
if row >= 0:
|
|
|
|
|
index = self.index(row, 0)
|
|
|
|
|
self.dataChanged.emit(index, index, [Qt.CheckStateRole])
|
|
|
|
|
self.checkedDeviceChanged.emit(serial)
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def checked_serial(self) -> str:
|
|
|
|
|
return self._checked_serial
|
|
|
|
|
|
|
|
|
|
def row_for_serial(self, serial: str) -> int:
|
|
|
|
|
for row, device in enumerate(self._rows):
|
|
|
|
|
if device.serial == serial:
|
|
|
|
|
return row
|
|
|
|
|
return -1
|
|
|
|
|
|
|
|
|
|
def device_for_serial(self, serial: str) -> Optional[AndroidDeviceRow]:
|
|
|
|
|
row = self.row_for_serial(serial)
|
|
|
|
|
return self._rows[row] if row >= 0 else None
|
2026-08-06 12:06:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class SettingsPage(QWidget):
|
2026-08-06 15:31:05 +08:00
|
|
|
"""设备管理与后续应用设置的统一页面。"""
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 17:57:49 +08:00
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
parent=None,
|
|
|
|
|
settings_repository=None,
|
|
|
|
|
admin_gateway=None,
|
2026-08-07 11:53:03 +08:00
|
|
|
android_device_service=None,
|
2026-08-06 17:57:49 +08:00
|
|
|
):
|
2026-08-06 12:06:16 +08:00
|
|
|
super().__init__(parent)
|
|
|
|
|
self.setObjectName("settingsPage")
|
2026-08-06 15:31:05 +08:00
|
|
|
self._build_ui()
|
2026-08-06 12:06:16 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
# 延迟到控件创建完成后绑定,避免事件层在构造过程中访问半成品页面。
|
|
|
|
|
from .settings_ui_event import SettingsPageEventBinder
|
|
|
|
|
|
2026-08-06 17:57:49 +08:00
|
|
|
self.eventBinder = SettingsPageEventBinder(
|
|
|
|
|
self,
|
|
|
|
|
settings_repository=settings_repository,
|
|
|
|
|
admin_gateway=admin_gateway,
|
2026-08-07 11:53:03 +08:00
|
|
|
android_device_service=android_device_service,
|
2026-08-06 17:57:49 +08:00
|
|
|
)
|
2026-08-06 15:31:05 +08:00
|
|
|
|
|
|
|
|
def _build_ui(self) -> None:
|
|
|
|
|
self.deviceIdInput = LineEdit(self)
|
|
|
|
|
self.deviceIdInput.setText("待生成")
|
|
|
|
|
self.deviceIdInput.setReadOnly(True)
|
|
|
|
|
self.deviceIdInput.setAccessibleName("当前客户端设备号")
|
|
|
|
|
|
|
|
|
|
self.deviceNameInput = LineEdit(self)
|
|
|
|
|
self.deviceNameInput.setPlaceholderText("请输入便于识别的设备名")
|
|
|
|
|
self.deviceNameInput.setClearButtonEnabled(True)
|
|
|
|
|
self.deviceNameInput.setMaxLength(50)
|
|
|
|
|
self.deviceNameInput.setAccessibleName("当前客户端设备名")
|
|
|
|
|
|
2026-08-06 15:57:59 +08:00
|
|
|
self.currentDeviceSaveButton = PushButton(FIF.SAVE, "保存", self)
|
|
|
|
|
self.currentDeviceSaveButton.setAccessibleName("保存当前设备信息")
|
2026-08-06 17:57:49 +08:00
|
|
|
self.currentDeviceStatusLabel = CaptionLabel(
|
|
|
|
|
"设备信息尚未保存", self
|
|
|
|
|
)
|
|
|
|
|
self.currentDeviceStatusLabel.setAccessibleName("当前设备保存状态")
|
2026-08-07 15:54:12 +08:00
|
|
|
self.currentDeviceStatusLabel.setWordWrap(True)
|
2026-08-06 15:57:59 +08:00
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
self.currentDeviceCard = self._build_current_device_card()
|
|
|
|
|
|
|
|
|
|
self.searchButton = PushButton(FIF.SEARCH, "搜索", self)
|
2026-08-07 14:42:00 +08:00
|
|
|
self.convertWifiButton = PushButton(FIF.WIFI, "转为 Wi-Fi", self)
|
|
|
|
|
self.convertWifiButton.setAccessibleName(
|
|
|
|
|
"将勾选的 USB Android 设备转为 Wi-Fi 连接"
|
|
|
|
|
)
|
|
|
|
|
self.convertWifiButton.setToolTip(
|
|
|
|
|
"开启 ADB 5555,并在拔掉 USB 后重新连接"
|
|
|
|
|
)
|
2026-08-06 15:31:05 +08:00
|
|
|
self.saveButton = PushButton(FIF.SAVE, "保存", self)
|
|
|
|
|
self.deleteButton = PushButton(FIF.DELETE, "删除", self)
|
2026-08-07 14:42:00 +08:00
|
|
|
self.convertWifiButton.setEnabled(False)
|
2026-08-06 15:31:05 +08:00
|
|
|
self.saveButton.setEnabled(False)
|
|
|
|
|
self.deleteButton.setEnabled(False)
|
|
|
|
|
|
|
|
|
|
self.deviceTableModel = AndroidDeviceTableModel(self)
|
|
|
|
|
self.deviceTable = TableView(self)
|
|
|
|
|
self.deviceTable.setModel(self.deviceTableModel)
|
|
|
|
|
self.deviceTable.setAccessibleName("已连接的 Android 设备")
|
|
|
|
|
self.deviceTable.setSelectionBehavior(QAbstractItemView.SelectRows)
|
|
|
|
|
self.deviceTable.setSelectionMode(QAbstractItemView.SingleSelection)
|
|
|
|
|
self.deviceTable.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
|
|
|
|
self.deviceTable.verticalHeader().hide()
|
|
|
|
|
self.deviceTable.verticalHeader().setDefaultSectionSize(42)
|
|
|
|
|
self.deviceTable.setMinimumHeight(250)
|
|
|
|
|
self.deviceTable.setColumnWidth(0, 64)
|
|
|
|
|
self.deviceTable.setColumnWidth(1, 210)
|
|
|
|
|
self.deviceTable.setColumnWidth(2, 96)
|
|
|
|
|
self.deviceTable.setColumnWidth(4, 112)
|
2026-08-06 15:50:47 +08:00
|
|
|
self.deviceTable.viewport().installEventFilter(self)
|
2026-08-06 15:31:05 +08:00
|
|
|
header = self.deviceTable.horizontalHeader()
|
|
|
|
|
header.setSectionResizeMode(0, QHeaderView.Fixed)
|
|
|
|
|
header.setSectionResizeMode(1, QHeaderView.Interactive)
|
|
|
|
|
header.setSectionResizeMode(2, QHeaderView.Fixed)
|
|
|
|
|
header.setSectionResizeMode(3, QHeaderView.Stretch)
|
|
|
|
|
header.setSectionResizeMode(4, QHeaderView.Fixed)
|
|
|
|
|
header.setSectionResizeMode(5, QHeaderView.ResizeToContents)
|
|
|
|
|
|
|
|
|
|
self.deviceStatusLabel = CaptionLabel("当前使用设备:未选择", self)
|
2026-08-07 11:53:03 +08:00
|
|
|
self.deviceStatusLabel.setAccessibleName("Android 设备搜索和选择状态")
|
2026-08-07 15:54:12 +08:00
|
|
|
self.deviceStatusLabel.setWordWrap(True)
|
|
|
|
|
self.pddAppStatusLabel = CaptionLabel("未检测", self)
|
|
|
|
|
self.pddAppStatusLabel.setAccessibleName("PDD 应用安装状态")
|
|
|
|
|
self.pddAppStatusLabel.setWordWrap(True)
|
2026-08-06 15:31:05 +08:00
|
|
|
self.androidDeviceCard = self._build_android_device_card()
|
|
|
|
|
|
|
|
|
|
content = QWidget(self)
|
|
|
|
|
content.setObjectName("settingsContent")
|
|
|
|
|
contentLayout = QVBoxLayout(content)
|
|
|
|
|
contentLayout.setContentsMargins(36, 30, 36, 36)
|
|
|
|
|
contentLayout.setSpacing(16)
|
|
|
|
|
contentLayout.addWidget(TitleLabel("设置", content))
|
|
|
|
|
contentLayout.addWidget(self.currentDeviceCard)
|
|
|
|
|
contentLayout.addWidget(self.androidDeviceCard)
|
|
|
|
|
contentLayout.addStretch(1)
|
|
|
|
|
|
|
|
|
|
scrollArea = ScrollArea(self)
|
|
|
|
|
scrollArea.setWidgetResizable(True)
|
|
|
|
|
scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
|
|
|
scrollArea.setWidget(content)
|
|
|
|
|
scrollArea.enableTransparentBackground()
|
2026-08-06 12:06:16 +08:00
|
|
|
|
|
|
|
|
layout = QVBoxLayout(self)
|
2026-08-06 15:31:05 +08:00
|
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
|
layout.addWidget(scrollArea)
|
|
|
|
|
|
2026-08-06 15:50:47 +08:00
|
|
|
def eventFilter(self, watched, event):
|
|
|
|
|
if watched is self.deviceTable.viewport() and event.type() == QEvent.Resize:
|
|
|
|
|
self._update_device_placeholder_rows()
|
|
|
|
|
return super().eventFilter(watched, event)
|
|
|
|
|
|
|
|
|
|
def _update_device_placeholder_rows(self) -> None:
|
|
|
|
|
"""用不可交互空行填满 Android 设备表格的可视区域。"""
|
|
|
|
|
|
|
|
|
|
row_height = max(1, self.deviceTable.verticalHeader().defaultSectionSize())
|
|
|
|
|
viewport_height = max(row_height, self.deviceTable.viewport().height())
|
|
|
|
|
row_count = max(1, viewport_height // row_height)
|
|
|
|
|
self.deviceTableModel.set_placeholder_row_count(row_count)
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def _build_current_device_card(self) -> CardWidget:
|
|
|
|
|
card = CardWidget(self)
|
|
|
|
|
card.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
|
|
|
|
layout = QVBoxLayout(card)
|
|
|
|
|
layout.setContentsMargins(24, 20, 24, 22)
|
|
|
|
|
layout.setSpacing(12)
|
2026-08-07 15:54:12 +08:00
|
|
|
|
|
|
|
|
titleLayout = QHBoxLayout()
|
|
|
|
|
titleLayout.setSpacing(12)
|
|
|
|
|
titleLayout.addWidget(SubtitleLabel("当前设备", card))
|
|
|
|
|
titleLayout.addStretch(1)
|
|
|
|
|
titleLayout.addWidget(self.currentDeviceStatusLabel, 1)
|
|
|
|
|
layout.addLayout(titleLayout)
|
2026-08-06 15:31:05 +08:00
|
|
|
|
|
|
|
|
form = QFormLayout()
|
|
|
|
|
form.setHorizontalSpacing(16)
|
|
|
|
|
form.setVerticalSpacing(12)
|
|
|
|
|
deviceIdLabel = CaptionLabel("设备号", card)
|
|
|
|
|
deviceIdLabel.setBuddy(self.deviceIdInput)
|
|
|
|
|
deviceNameLabel = CaptionLabel("设备名", card)
|
|
|
|
|
deviceNameLabel.setBuddy(self.deviceNameInput)
|
|
|
|
|
form.addRow(deviceIdLabel, self.deviceIdInput)
|
|
|
|
|
form.addRow(deviceNameLabel, self.deviceNameInput)
|
|
|
|
|
layout.addLayout(form)
|
2026-08-06 15:57:59 +08:00
|
|
|
|
|
|
|
|
commandLayout = QHBoxLayout()
|
|
|
|
|
commandLayout.addStretch(1)
|
|
|
|
|
commandLayout.addWidget(self.currentDeviceSaveButton)
|
|
|
|
|
layout.addLayout(commandLayout)
|
2026-08-06 15:31:05 +08:00
|
|
|
return card
|
|
|
|
|
|
|
|
|
|
def _build_android_device_card(self) -> CardWidget:
|
|
|
|
|
card = CardWidget(self)
|
|
|
|
|
layout = QVBoxLayout(card)
|
|
|
|
|
layout.setContentsMargins(24, 20, 24, 22)
|
|
|
|
|
layout.setSpacing(12)
|
|
|
|
|
|
2026-08-07 15:54:12 +08:00
|
|
|
titleLayout = QHBoxLayout()
|
|
|
|
|
titleLayout.setSpacing(12)
|
|
|
|
|
titleLayout.addWidget(SubtitleLabel("Android 设备", card))
|
|
|
|
|
titleLayout.addStretch(1)
|
|
|
|
|
titleLayout.addWidget(self.deviceStatusLabel, 1)
|
|
|
|
|
layout.addLayout(titleLayout)
|
|
|
|
|
|
|
|
|
|
pddStatusLayout = QHBoxLayout()
|
|
|
|
|
pddStatusLayout.setSpacing(12)
|
|
|
|
|
pddStatusLayout.addWidget(CaptionLabel("PDD 应用", card))
|
|
|
|
|
pddStatusLayout.addWidget(self.pddAppStatusLabel, 1)
|
|
|
|
|
layout.addLayout(pddStatusLayout)
|
2026-08-06 15:31:05 +08:00
|
|
|
|
|
|
|
|
commandLayout = QHBoxLayout()
|
|
|
|
|
commandLayout.setSpacing(10)
|
|
|
|
|
commandLayout.addWidget(self.searchButton)
|
2026-08-07 14:42:00 +08:00
|
|
|
commandLayout.addWidget(self.convertWifiButton)
|
2026-08-06 15:31:05 +08:00
|
|
|
commandLayout.addStretch(1)
|
|
|
|
|
commandLayout.addWidget(self.saveButton)
|
|
|
|
|
commandLayout.addWidget(self.deleteButton)
|
|
|
|
|
layout.addLayout(commandLayout)
|
|
|
|
|
layout.addWidget(self.deviceTable, 1)
|
|
|
|
|
return card
|
|
|
|
|
|
|
|
|
|
def set_client_info(self, device_id: str, device_name: str) -> None:
|
|
|
|
|
"""显示后续设备身份服务提供的当前客户端信息。"""
|
|
|
|
|
|
|
|
|
|
self.deviceIdInput.setText(device_id or "待生成")
|
|
|
|
|
self.deviceNameInput.setText(device_name)
|
|
|
|
|
|
2026-08-06 17:57:49 +08:00
|
|
|
def set_current_device_status(self, message: str) -> None:
|
|
|
|
|
"""显示本地保存和 Admin 登记两个阶段的结果。"""
|
|
|
|
|
|
|
|
|
|
self.currentDeviceStatusLabel.setText(message)
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def set_android_devices(self, devices: Iterable[AndroidDeviceRow]) -> None:
|
|
|
|
|
"""显示后续 ADB 服务返回的设备列表。"""
|
|
|
|
|
|
|
|
|
|
self.deviceTableModel.set_devices(devices)
|
2026-08-06 15:50:47 +08:00
|
|
|
self._update_device_placeholder_rows()
|
2026-08-06 15:31:05 +08:00
|
|
|
|
2026-08-07 15:54:12 +08:00
|
|
|
def set_pdd_app_status(self, message: str) -> None:
|
|
|
|
|
"""显示当前勾选设备上的 PDD 安装检测结果。"""
|
|
|
|
|
|
|
|
|
|
self.pddAppStatusLabel.setText(message)
|
|
|
|
|
|
2026-08-06 15:31:05 +08:00
|
|
|
def set_saved_android_device(self, serial: str) -> None:
|
|
|
|
|
"""显示已经保存并实际用于自动化的 Android 设备。"""
|
|
|
|
|
|
|
|
|
|
self.deviceTableModel.set_checked_serial(serial)
|
|
|
|
|
text = serial if serial else "未选择"
|
|
|
|
|
self.deviceStatusLabel.setText(f"当前使用设备:{text}")
|