feat: track settings changes and enforce Chinese UI copy
This commit is contained in:
+118
-6
@@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ..widgets import *
|
||||
from ..workers import AIModelTestWorker as _RealAIModelTestWorker
|
||||
from ..workers import CMHubSettingsWorker as _RealCMHubSettingsWorker
|
||||
@@ -63,6 +65,8 @@ class SettingsTab(QWidget):
|
||||
self._loaded_cmhub_api_key = ""
|
||||
self._cmhub_auto_refresh_done = False
|
||||
self._compat_test_item_id = ""
|
||||
self._dirty = False
|
||||
self._suspend_dirty = 0
|
||||
|
||||
self.backend_combo = QComboBox()
|
||||
self.backend_combo.setObjectName("aiBackendCombo")
|
||||
@@ -173,6 +177,10 @@ class SettingsTab(QWidget):
|
||||
self.cdp_ready_timeout_spin.setObjectName("cdpReadyTimeoutSpin")
|
||||
self.cdp_ready_timeout_spin.setRange(1, 3600)
|
||||
self.save_config_button = QPushButton("保存设置")
|
||||
self.unsaved_changes_label = QLabel("● 未保存更改")
|
||||
self.unsaved_changes_label.setObjectName("settingsUnsavedChangesLabel")
|
||||
self.unsaved_changes_label.setStyleSheet("color: #bc4c00; font-weight: 600;")
|
||||
self.unsaved_changes_label.setVisible(False)
|
||||
self.allow_real_submit_checkbox = QCheckBox("允许真实提交线上商品")
|
||||
self.allow_real_submit_checkbox.setObjectName("allowRealSubmitCheckbox")
|
||||
self.allow_cover_update_checkbox = QCheckBox("允许更新封面")
|
||||
@@ -351,7 +359,12 @@ class SettingsTab(QWidget):
|
||||
panel_layout.addSpacing(18)
|
||||
panel_layout.addWidget(self.infrastructure_section_title)
|
||||
panel_layout.addLayout(path_form)
|
||||
panel_layout.addWidget(self.save_config_button)
|
||||
save_settings_layout = QHBoxLayout()
|
||||
save_settings_layout.setContentsMargins(0, 0, 0, 0)
|
||||
save_settings_layout.addWidget(self.save_config_button)
|
||||
save_settings_layout.addWidget(self.unsaved_changes_label)
|
||||
save_settings_layout.addStretch(1)
|
||||
panel_layout.addLayout(save_settings_layout)
|
||||
panel_layout.addStretch(1)
|
||||
|
||||
scroll = QScrollArea()
|
||||
@@ -380,9 +393,12 @@ class SettingsTab(QWidget):
|
||||
self._update_response_timeout_label
|
||||
)
|
||||
self.save_config_button.clicked.connect(self.save_app_settings)
|
||||
self._connect_dirty_signals()
|
||||
|
||||
self.refresh_models()
|
||||
self._populate_app_settings()
|
||||
with self._dirty_tracking_suspended():
|
||||
self.refresh_models()
|
||||
self._populate_app_settings()
|
||||
self._set_dirty(False)
|
||||
|
||||
def _three_column_form(self, fields):
|
||||
layout = QGridLayout()
|
||||
@@ -436,6 +452,92 @@ class SettingsTab(QWidget):
|
||||
if self.status_callback is not None:
|
||||
self.status_callback(message)
|
||||
|
||||
@contextmanager
|
||||
def _dirty_tracking_suspended(self):
|
||||
self._suspend_dirty += 1
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
self._suspend_dirty -= 1
|
||||
|
||||
def _connect_dirty_signals(self):
|
||||
line_edits = (
|
||||
self.cmhub_base_url_edit,
|
||||
self.cmhub_api_key_edit,
|
||||
self.name_edit,
|
||||
self.model_id_edit,
|
||||
self.url_edit,
|
||||
self.api_key_edit,
|
||||
self.chrome_path_edit,
|
||||
self.user_data_root_edit,
|
||||
self.image_dir_edit,
|
||||
self.db_path_edit,
|
||||
)
|
||||
combos = (
|
||||
self.backend_combo,
|
||||
self.cmhub_title_alias_combo,
|
||||
self.cmhub_image_alias_combo,
|
||||
self.category_combo,
|
||||
self.api_type_combo,
|
||||
self.default_text_model_combo,
|
||||
self.default_image_model_combo,
|
||||
self.resolution_combo,
|
||||
)
|
||||
spin_boxes = (
|
||||
self.cmhub_connect_timeout_spin,
|
||||
self.connect_timeout_spin,
|
||||
self.title_concurrency_spin,
|
||||
self.image_concurrency_spin,
|
||||
self.retry_spin,
|
||||
self.jpg_quality_spin,
|
||||
self.default_debug_port_spin,
|
||||
self.debug_port_start_spin,
|
||||
self.debug_port_end_spin,
|
||||
self.cdp_ready_timeout_spin,
|
||||
self.max_items_per_run_spin,
|
||||
self.max_parallel_accounts_spin,
|
||||
)
|
||||
checkboxes = (
|
||||
self.cmhub_check_balance_checkbox,
|
||||
self.enabled_checkbox,
|
||||
self.allow_real_submit_checkbox,
|
||||
self.allow_cover_update_checkbox,
|
||||
self.close_success_tab_checkbox,
|
||||
self.parallel_accounts_checkbox,
|
||||
)
|
||||
for widget in line_edits:
|
||||
widget.textChanged.connect(self._mark_dirty)
|
||||
for widget in combos:
|
||||
widget.currentIndexChanged.connect(self._mark_dirty)
|
||||
for widget in spin_boxes:
|
||||
widget.valueChanged.connect(self._mark_dirty)
|
||||
for widget in checkboxes:
|
||||
widget.toggled.connect(self._mark_dirty)
|
||||
|
||||
def _mark_dirty(self, *args):
|
||||
if self._suspend_dirty > 0:
|
||||
return
|
||||
self._set_dirty(True)
|
||||
|
||||
def _set_dirty(self, dirty):
|
||||
self._dirty = bool(dirty)
|
||||
self.unsaved_changes_label.setVisible(self._dirty)
|
||||
|
||||
def is_dirty(self):
|
||||
return self._dirty
|
||||
|
||||
def discard_unsaved_changes(self):
|
||||
try:
|
||||
saved = appconfig.load_config(self.config_path)
|
||||
except Exception as exc:
|
||||
self._show_error(exc)
|
||||
return False
|
||||
self._replace_config(saved)
|
||||
self._populate_app_settings()
|
||||
self._set_dirty(False)
|
||||
self._set_status("已放弃未保存更改")
|
||||
return True
|
||||
|
||||
def _maybe_auto_refresh_cmhub_models(self):
|
||||
if self._cmhub_auto_refresh_done:
|
||||
return
|
||||
@@ -594,7 +696,7 @@ class SettingsTab(QWidget):
|
||||
def save_app_settings(self, checked=False):
|
||||
settings = self._app_settings_values()
|
||||
if settings is None:
|
||||
return
|
||||
return False
|
||||
cmhub_key = self.cmhub_api_key_edit.text()
|
||||
if self._should_warn_plaintext_cmhub_api_key(cmhub_key):
|
||||
self._show_plaintext_cmhub_api_key_warning()
|
||||
@@ -606,11 +708,13 @@ class SettingsTab(QWidget):
|
||||
saved = appconfig.save_config(settings, path=self.config_path)
|
||||
except Exception as exc:
|
||||
self._show_error(exc)
|
||||
return
|
||||
return False
|
||||
self._replace_config(saved)
|
||||
self._populate_app_settings()
|
||||
self._set_dirty(False)
|
||||
self._set_status("设置已保存")
|
||||
QMessageBox.information(self, "保存设置", "设置已保存")
|
||||
return True
|
||||
|
||||
def _app_settings_values(self):
|
||||
start_port = self.debug_port_start_spin.value()
|
||||
@@ -700,6 +804,10 @@ class SettingsTab(QWidget):
|
||||
self.config.update(internal)
|
||||
|
||||
def _populate_app_settings(self):
|
||||
if self._suspend_dirty <= 0:
|
||||
with self._dirty_tracking_suspended():
|
||||
self._populate_app_settings()
|
||||
return
|
||||
self._populate_role_model_combos()
|
||||
ai_cfg = appconfig.ai_config(self.config)
|
||||
self._set_combo_by_data(self.backend_combo, "cmhub")
|
||||
@@ -1011,7 +1119,7 @@ class SettingsTab(QWidget):
|
||||
image_count = self._cmhub_alias_count("image")
|
||||
balance = payload.get("points_balance")
|
||||
balance_text = f";余额 {balance}" if balance is not None else ""
|
||||
message = f"cmhub 连接成功:生文别名 {title_count} 个,生图别名 {image_count} 个{balance_text}"
|
||||
message = f"cmhub 连接成功:生文别名 {title_count} 个,生图别名 {image_count} 个{balance_text};别名已拉取,记得点『保存设置』持久化"
|
||||
self.cmhub_result_label.setText(message)
|
||||
self._set_status(message)
|
||||
|
||||
@@ -1021,6 +1129,10 @@ class SettingsTab(QWidget):
|
||||
self._set_status(message)
|
||||
|
||||
def _populate_cmhub_alias_combos(self, models, title_selected="", image_selected=""):
|
||||
if self._suspend_dirty <= 0:
|
||||
with self._dirty_tracking_suspended():
|
||||
self._populate_cmhub_alias_combos(models, title_selected, image_selected)
|
||||
return
|
||||
self._populate_cmhub_alias_combo(
|
||||
self.cmhub_title_alias_combo,
|
||||
models,
|
||||
|
||||
Reference in New Issue
Block a user