feat: add chrome path picker
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
|
||||
from ... import ai as ai_module
|
||||
from ..widgets import *
|
||||
@@ -165,6 +166,15 @@ class SettingsTab(QWidget):
|
||||
self.jpg_quality_spin.setRange(1, 100)
|
||||
self.chrome_path_edit = QLineEdit()
|
||||
self.chrome_path_edit.setObjectName("chromePathEdit")
|
||||
self.chrome_path_browse_button = QPushButton("选择...")
|
||||
self.chrome_path_browse_button.setObjectName("chromePathBrowseButton")
|
||||
self.chrome_path_widget = QWidget()
|
||||
self.chrome_path_widget.setObjectName("chromePathWidget")
|
||||
chrome_path_layout = QHBoxLayout(self.chrome_path_widget)
|
||||
chrome_path_layout.setContentsMargins(0, 0, 0, 0)
|
||||
chrome_path_layout.setSpacing(8)
|
||||
chrome_path_layout.addWidget(self.chrome_path_edit, 1)
|
||||
chrome_path_layout.addWidget(self.chrome_path_browse_button)
|
||||
self.user_data_root_edit = QLineEdit()
|
||||
self.user_data_root_edit.setObjectName("userDataRootEdit")
|
||||
self.user_data_root_edit.setEnabled(False)
|
||||
@@ -271,7 +281,7 @@ class SettingsTab(QWidget):
|
||||
|
||||
path_form = self._three_column_form(
|
||||
[
|
||||
("Chrome路径", self.chrome_path_edit, True),
|
||||
("Chrome路径", self.chrome_path_widget, True),
|
||||
("默认调试端口", self.default_debug_port_spin),
|
||||
("调试端口范围", port_range_widget),
|
||||
("CDP就绪超时(秒)", self.cdp_ready_timeout_spin),
|
||||
@@ -403,6 +413,7 @@ class SettingsTab(QWidget):
|
||||
self.resolution_combo.currentIndexChanged.connect(
|
||||
self._update_response_timeout_label
|
||||
)
|
||||
self.chrome_path_browse_button.clicked.connect(self.browse_chrome_path)
|
||||
self.save_config_button.clicked.connect(self.save_app_settings)
|
||||
self._connect_dirty_signals()
|
||||
|
||||
@@ -533,6 +544,23 @@ class SettingsTab(QWidget):
|
||||
def is_dirty(self):
|
||||
return self._dirty
|
||||
|
||||
def browse_chrome_path(self, checked=False):
|
||||
current = self.chrome_path_edit.text().strip()
|
||||
initial_dir = ""
|
||||
if current:
|
||||
parent_dir = os.path.dirname(os.path.expanduser(current))
|
||||
if parent_dir and os.path.isdir(parent_dir):
|
||||
initial_dir = parent_dir
|
||||
path, _selected_filter = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
"选择 Chrome 程序",
|
||||
initial_dir,
|
||||
"Chrome 程序 (chrome.exe);;可执行文件 (*.exe);;所有文件 (*)",
|
||||
)
|
||||
if not path:
|
||||
return
|
||||
self.chrome_path_edit.setText(path)
|
||||
|
||||
def discard_unsaved_changes(self):
|
||||
try:
|
||||
saved = appconfig.load_config(self.config_path)
|
||||
|
||||
+9
-1
@@ -3,7 +3,7 @@ id: T-557
|
||||
title: ⑤设置 Chrome 路径增加文件选择按钮
|
||||
phase: 7
|
||||
deps: [T-539, T-543]
|
||||
status: TODO
|
||||
status: DONE
|
||||
created: 2026-07-08
|
||||
---
|
||||
|
||||
@@ -44,3 +44,11 @@ created: 2026-07-08
|
||||
## 边界(不改什么)
|
||||
|
||||
只改⑤设置页 Chrome 路径的 GUI 选择入口和测试;不改 `config.json` schema、不改 `appconfig.chrome_path()`、不改 `app/chrome.py` 启动参数、不改④账号管理、不改 CDP/Shopee 逻辑、不引入自动搜索/自动安装/自动启动 Chrome。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-08:⑤设置页「Chrome路径」改为输入框 + `选择...` 按钮的横向控件,按钮对象名为 `chromePathBrowseButton`。
|
||||
- 2026-07-08:点击 `选择...` 后调用 `QFileDialog.getOpenFileName()`,中文标题为「选择 Chrome 程序」,过滤 `chrome.exe` / `*.exe`;选中文件后回填 `chromePathEdit` 并沿用现有未保存状态机制,取消不改变路径。
|
||||
- 2026-07-08:保存逻辑仍复用现有 `save_app_settings()`,所选路径写入 `config.json` 的 `chrome_path`,未改配置 schema、Chrome 启动、账号管理或 CDP。
|
||||
- 2026-07-08:更新 GUI 单测,覆盖按钮存在、布局、选择回填、取消不改值、选择后保存写入配置。
|
||||
- 验证通过:`python -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`py -3.10 -m unittest discover -s tests`、`git diff --check`。
|
||||
|
||||
+53
-1
@@ -733,9 +733,61 @@ class GuiTests(TempDirMixin, unittest.TestCase):
|
||||
self.assertFalse(hidden_widget.isEnabled())
|
||||
self.assertEqual(-1, tab.infrastructure_form_layout.indexOf(hidden_widget))
|
||||
self.assertGreaterEqual(
|
||||
tab.infrastructure_form_layout.indexOf(tab.chrome_path_edit),
|
||||
tab.infrastructure_form_layout.indexOf(tab.chrome_path_widget),
|
||||
0,
|
||||
)
|
||||
self.assertEqual("选择...", tab.chrome_path_browse_button.text())
|
||||
self.assertEqual("chromePathBrowseButton", tab.chrome_path_browse_button.objectName())
|
||||
self.assertIs(
|
||||
tab.chrome_path_widget.layout().itemAt(0).widget(),
|
||||
tab.chrome_path_edit,
|
||||
)
|
||||
self.assertIs(
|
||||
tab.chrome_path_widget.layout().itemAt(1).widget(),
|
||||
tab.chrome_path_browse_button,
|
||||
)
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
def test_settings_tab_browses_chrome_path(self):
|
||||
with self.make_temp_dir() as temp_dir:
|
||||
cfg = self.make_config(temp_dir)
|
||||
statuses = []
|
||||
tab = SettingsTab(config=cfg, status_callback=statuses.append)
|
||||
self.addCleanup(tab.close)
|
||||
selected_path = os.path.join(temp_dir, "Chrome", "chrome.exe")
|
||||
os.makedirs(os.path.dirname(selected_path), exist_ok=True)
|
||||
|
||||
self.assertFalse(tab.is_dirty())
|
||||
with mock.patch(
|
||||
"app.gui.tabs.settings.QFileDialog.getOpenFileName",
|
||||
return_value=(selected_path, "Chrome 程序 (chrome.exe)"),
|
||||
) as browse:
|
||||
tab.chrome_path_browse_button.click()
|
||||
|
||||
browse.assert_called_once()
|
||||
self.assertEqual("选择 Chrome 程序", browse.call_args[0][1])
|
||||
self.assertEqual(selected_path, tab.chrome_path_edit.text())
|
||||
self.assertTrue(tab.is_dirty())
|
||||
self.assertFalse(tab.unsaved_changes_label.isHidden())
|
||||
|
||||
with mock.patch("app.gui.QMessageBox.information") as info:
|
||||
self.assertTrue(tab.save_app_settings())
|
||||
info.assert_called_once_with(tab, "保存设置", "设置已保存")
|
||||
saved = appconfig.load_config(cfg["config_path"])
|
||||
self.assertEqual(selected_path, saved["chrome_path"])
|
||||
self.assertFalse(tab.is_dirty())
|
||||
|
||||
tab._set_dirty(False)
|
||||
previous_path = tab.chrome_path_edit.text()
|
||||
with mock.patch(
|
||||
"app.gui.tabs.settings.QFileDialog.getOpenFileName",
|
||||
return_value=("", ""),
|
||||
):
|
||||
tab.chrome_path_browse_button.click()
|
||||
|
||||
self.assertEqual(previous_path, tab.chrome_path_edit.text())
|
||||
self.assertFalse(tab.is_dirty())
|
||||
|
||||
self.assert_removed(temp_dir)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user