feat: Add branding import/export functionality and enhance settings dialog with new fields
Some checks are pending
Tests & Quality Checks / Test on Python 3.11 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.10 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-2 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-2 (push) Waiting to run
Tests & Quality Checks / Build Artifacts (push) Blocked by required conditions
Tests & Quality Checks / Build Artifacts-1 (push) Blocked by required conditions
Some checks are pending
Tests & Quality Checks / Test on Python 3.11 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.10 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-2 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-2 (push) Waiting to run
Tests & Quality Checks / Build Artifacts (push) Blocked by required conditions
Tests & Quality Checks / Build Artifacts-1 (push) Blocked by required conditions
This commit is contained in:
parent
b826bd9b20
commit
55f2ddf4b1
10 changed files with 296 additions and 10 deletions
|
|
@ -198,6 +198,20 @@ class SettingsDialog(QDialog):
|
|||
layout.addWidget(QLabel(tr("settings.branding.display_name_label")))
|
||||
layout.addWidget(self.branding_display_name_input)
|
||||
|
||||
self.branding_app_name_input = QLineEdit()
|
||||
self.branding_app_name_input.setPlaceholderText(tr("settings.branding.app_name_label"))
|
||||
self.branding_app_name_input.textChanged.connect(self._update_branding_preview)
|
||||
layout.addWidget(QLabel(tr("settings.branding.app_name_label")))
|
||||
layout.addWidget(self.branding_app_name_input)
|
||||
|
||||
self.branding_window_title_input = QLineEdit()
|
||||
self.branding_window_title_input.setPlaceholderText(
|
||||
tr("settings.branding.window_title_label")
|
||||
)
|
||||
self.branding_window_title_input.textChanged.connect(self._update_branding_preview)
|
||||
layout.addWidget(QLabel(tr("settings.branding.window_title_label")))
|
||||
layout.addWidget(self.branding_window_title_input)
|
||||
|
||||
layout.addWidget(QLabel(tr("settings.branding.logo_path_label")))
|
||||
logo_layout = QHBoxLayout()
|
||||
self.branding_logo_path_input = QLineEdit()
|
||||
|
|
@ -215,6 +229,10 @@ class SettingsDialog(QDialog):
|
|||
self.branding_preview_name_label.setStyleSheet("font-weight: bold;")
|
||||
layout.addWidget(self.branding_preview_name_label)
|
||||
|
||||
self.branding_preview_title_label = QLabel()
|
||||
self.branding_preview_title_label.setStyleSheet("color: gray;")
|
||||
layout.addWidget(self.branding_preview_title_label)
|
||||
|
||||
self.branding_preview_icon_label = QLabel(tr("settings.branding.no_icon_selected"))
|
||||
self.branding_preview_icon_label.setFixedSize(72, 72)
|
||||
self.branding_preview_icon_label.setStyleSheet(
|
||||
|
|
@ -227,6 +245,14 @@ class SettingsDialog(QDialog):
|
|||
self.save_branding_as_btn.clicked.connect(self._save_branding_as)
|
||||
branding_button_layout.addWidget(self.save_branding_as_btn)
|
||||
|
||||
self.export_branding_btn = QPushButton(tr("settings.branding.export_btn"))
|
||||
self.export_branding_btn.clicked.connect(self._export_branding)
|
||||
branding_button_layout.addWidget(self.export_branding_btn)
|
||||
|
||||
self.import_branding_btn = QPushButton(tr("settings.branding.import_btn"))
|
||||
self.import_branding_btn.clicked.connect(self._import_branding)
|
||||
branding_button_layout.addWidget(self.import_branding_btn)
|
||||
|
||||
self.delete_branding_btn = QPushButton(tr("settings.branding.delete_btn"))
|
||||
self.delete_branding_btn.clicked.connect(self._delete_branding)
|
||||
branding_button_layout.addWidget(self.delete_branding_btn)
|
||||
|
|
@ -262,9 +288,30 @@ class SettingsDialog(QDialog):
|
|||
"""Load the selected branding into the editable fields."""
|
||||
template = self.branding_manager.load_template(template_id)
|
||||
self.branding_display_name_input.setText(template.display_name)
|
||||
self.branding_logo_path_input.setText(template.logo_path)
|
||||
self.branding_app_name_input.setText(template.app_name)
|
||||
self.branding_window_title_input.setText(
|
||||
template.window_title or f"{template.app_name} v{self.config.app_version}"
|
||||
)
|
||||
self.branding_logo_path_input.setText(template.logo_path or template.get_app_icon_path())
|
||||
self._update_branding_preview()
|
||||
|
||||
def _resolve_branding_preview_path(self, configured_path: str) -> Optional[Path]:
|
||||
"""Resolve a branding preview path in both dev and packaged layouts."""
|
||||
if not configured_path:
|
||||
return None
|
||||
|
||||
path = Path(configured_path)
|
||||
candidates = [path] if path.is_absolute() else [Path.cwd() / path]
|
||||
if not path.is_absolute():
|
||||
project_root = Path(__file__).resolve().parents[3]
|
||||
candidates.append(project_root / path)
|
||||
|
||||
for candidate in candidates:
|
||||
if candidate.exists() and candidate.is_file():
|
||||
return candidate
|
||||
|
||||
return None
|
||||
|
||||
def _update_branding_preview(self) -> None:
|
||||
"""Refresh the small branding preview for name and icon."""
|
||||
display_name = self.branding_display_name_input.text().strip() or tr(
|
||||
|
|
@ -272,11 +319,17 @@ class SettingsDialog(QDialog):
|
|||
)
|
||||
self.branding_preview_name_label.setText(display_name)
|
||||
|
||||
effective_title = self.branding_window_title_input.text().strip() or (
|
||||
self.branding_app_name_input.text().strip() or display_name
|
||||
)
|
||||
self.branding_preview_title_label.setText(effective_title)
|
||||
|
||||
logo_path = self.branding_logo_path_input.text().strip()
|
||||
if logo_path and Path(logo_path).exists():
|
||||
pixmap = QPixmap(logo_path)
|
||||
resolved_logo_path = self._resolve_branding_preview_path(logo_path)
|
||||
if resolved_logo_path:
|
||||
pixmap = QPixmap(str(resolved_logo_path))
|
||||
if pixmap.isNull():
|
||||
icon = QIcon(logo_path)
|
||||
icon = QIcon(str(resolved_logo_path))
|
||||
pixmap = icon.pixmap(64, 64)
|
||||
|
||||
if not pixmap.isNull():
|
||||
|
|
@ -318,10 +371,13 @@ class SettingsDialog(QDialog):
|
|||
|
||||
try:
|
||||
display_name = self.branding_display_name_input.text().strip() or branding_name
|
||||
app_name = self.branding_app_name_input.text().strip() or display_name
|
||||
window_title = self.branding_window_title_input.text().strip()
|
||||
template = self.branding_manager.build_template(
|
||||
template_id=branding_name,
|
||||
display_name=display_name,
|
||||
app_name=display_name,
|
||||
app_name=app_name,
|
||||
window_title=window_title,
|
||||
logo_path=self.branding_logo_path_input.text(),
|
||||
)
|
||||
self.branding_manager.save_template(template)
|
||||
|
|
@ -330,6 +386,44 @@ class SettingsDialog(QDialog):
|
|||
except ConfigurationError as e:
|
||||
self._show_error(f"Failed to save branding: {e}")
|
||||
|
||||
def _export_branding(self) -> None:
|
||||
"""Export the selected branding so it can be shared with other users."""
|
||||
template_id = self.branding_combo.currentData()
|
||||
if not template_id:
|
||||
return
|
||||
|
||||
file_path, _ = QFileDialog.getSaveFileName(
|
||||
self,
|
||||
tr("settings.branding.export_title"),
|
||||
str(Path.home() / f"{template_id}.json"),
|
||||
"JSON Files (*.json);;All Files (*)",
|
||||
)
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
try:
|
||||
self.branding_manager.export_template(template_id, Path(file_path))
|
||||
except ConfigurationError as e:
|
||||
self._show_error(f"Failed to export branding: {e}")
|
||||
|
||||
def _import_branding(self) -> None:
|
||||
"""Import a branding package from another user."""
|
||||
file_path, _ = QFileDialog.getOpenFileName(
|
||||
self,
|
||||
tr("settings.branding.import_title"),
|
||||
str(Path.home()),
|
||||
"JSON Files (*.json);;All Files (*)",
|
||||
)
|
||||
if not file_path:
|
||||
return
|
||||
|
||||
try:
|
||||
template = self.branding_manager.import_template(Path(file_path))
|
||||
self._refresh_branding_combo(template.template_id)
|
||||
self._load_branding_into_editor(template.template_id)
|
||||
except ConfigurationError as e:
|
||||
self._show_error(f"Failed to import branding: {e}")
|
||||
|
||||
def _delete_branding(self) -> None:
|
||||
"""Delete the currently selected custom branding."""
|
||||
template_id = self.branding_combo.currentData()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue