feat: Add branding change prompts and corresponding translations for restart notifications
This commit is contained in:
parent
ca7105a6bc
commit
2ecd299f31
5 changed files with 79 additions and 15 deletions
|
|
@ -58,6 +58,10 @@
|
||||||
"dialog.language_changed.msg": "Die Spracheinstellung wurde aktualisiert. Starten Sie jetzt neu, um die ausgew\u00e4hlte Sprache \u00fcberall anzuwenden.",
|
"dialog.language_changed.msg": "Die Spracheinstellung wurde aktualisiert. Starten Sie jetzt neu, um die ausgew\u00e4hlte Sprache \u00fcberall anzuwenden.",
|
||||||
"dialog.language_changed.restart_now": "Jetzt neu starten",
|
"dialog.language_changed.restart_now": "Jetzt neu starten",
|
||||||
"dialog.language_changed.restart_later": "Sp\u00e4ter neu starten",
|
"dialog.language_changed.restart_later": "Sp\u00e4ter neu starten",
|
||||||
|
"dialog.branding_changed.title": "Branding ge\u00e4ndert",
|
||||||
|
"dialog.branding_changed.msg": "Das aktive Branding wurde geändert. Starten Sie jetzt neu, damit die aktualisierte visuelle Identität überall angewendet wird.",
|
||||||
|
"dialog.branding_changed.restart_now": "Jetzt neu starten",
|
||||||
|
"dialog.branding_changed.restart_later": "Sp\u00e4ter neu starten",
|
||||||
"dialog.restart_failed.title": "Neustart fehlgeschlagen",
|
"dialog.restart_failed.title": "Neustart fehlgeschlagen",
|
||||||
"dialog.restart_failed.msg": "Die Anwendung konnte nicht automatisch neu gestartet werden:\n\n{error}\n\nBitte starten Sie manuell neu.",
|
"dialog.restart_failed.msg": "Die Anwendung konnte nicht automatisch neu gestartet werden:\n\n{error}\n\nBitte starten Sie manuell neu.",
|
||||||
"dialog.update_timeout.title": "Zeitüberschreitung bei der Update-Pr\u00fcfung",
|
"dialog.update_timeout.title": "Zeitüberschreitung bei der Update-Pr\u00fcfung",
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@
|
||||||
"dialog.language_changed.msg": "The language setting was updated. Restart now to apply the selected language everywhere.",
|
"dialog.language_changed.msg": "The language setting was updated. Restart now to apply the selected language everywhere.",
|
||||||
"dialog.language_changed.restart_now": "Restart Now",
|
"dialog.language_changed.restart_now": "Restart Now",
|
||||||
"dialog.language_changed.restart_later": "Restart Later",
|
"dialog.language_changed.restart_later": "Restart Later",
|
||||||
|
"dialog.branding_changed.title": "Branding Changed",
|
||||||
|
"dialog.branding_changed.msg": "The active branding was changed. Restart now so the updated visual identity is applied everywhere.",
|
||||||
|
"dialog.branding_changed.restart_now": "Restart Now",
|
||||||
|
"dialog.branding_changed.restart_later": "Restart Later",
|
||||||
"dialog.restart_failed.title": "Restart Failed",
|
"dialog.restart_failed.title": "Restart Failed",
|
||||||
"dialog.restart_failed.msg": "Could not automatically restart the application:\n\n{error}\n\nPlease restart manually.",
|
"dialog.restart_failed.msg": "Could not automatically restart the application:\n\n{error}\n\nPlease restart manually.",
|
||||||
"dialog.update_timeout.title": "Update Check Timeout",
|
"dialog.update_timeout.title": "Update Check Timeout",
|
||||||
|
|
|
||||||
|
|
@ -1958,6 +1958,7 @@ class MainWindow(QMainWindow):
|
||||||
# Store current URL before opening dialog
|
# Store current URL before opening dialog
|
||||||
old_webapp_url = self.config.webapp_url
|
old_webapp_url = self.config.webapp_url
|
||||||
old_language = self.config.language
|
old_language = self.config.language
|
||||||
|
old_branding_id = self.config.active_branding_id
|
||||||
|
|
||||||
# Show dialog
|
# Show dialog
|
||||||
dialog = SettingsDialog(self.config, self)
|
dialog = SettingsDialog(self.config, self)
|
||||||
|
|
@ -1966,6 +1967,9 @@ class MainWindow(QMainWindow):
|
||||||
# Check if webapp URL changed
|
# Check if webapp URL changed
|
||||||
new_webapp_url = self.config.webapp_url
|
new_webapp_url = self.config.webapp_url
|
||||||
language_changed = old_language != self.config.language
|
language_changed = old_language != self.config.language
|
||||||
|
branding_changed = old_branding_id != self.config.active_branding_id
|
||||||
|
restart_prompt_shown = False
|
||||||
|
|
||||||
if old_webapp_url != new_webapp_url:
|
if old_webapp_url != new_webapp_url:
|
||||||
logger.info(f"Web application URL changed: {old_webapp_url} → {new_webapp_url}")
|
logger.info(f"Web application URL changed: {old_webapp_url} → {new_webapp_url}")
|
||||||
|
|
||||||
|
|
@ -1975,6 +1979,7 @@ class MainWindow(QMainWindow):
|
||||||
if domain_changed:
|
if domain_changed:
|
||||||
logger.warning("Domain has changed - recommending restart")
|
logger.warning("Domain has changed - recommending restart")
|
||||||
self._handle_domain_change_restart()
|
self._handle_domain_change_restart()
|
||||||
|
restart_prompt_shown = True
|
||||||
else:
|
else:
|
||||||
logger.info("Path changed but domain is same - reloading...")
|
logger.info("Path changed but domain is same - reloading...")
|
||||||
# Clear cache and navigate to home asynchronously
|
# Clear cache and navigate to home asynchronously
|
||||||
|
|
@ -1982,7 +1987,16 @@ class MainWindow(QMainWindow):
|
||||||
self.web_view.clear_cache_and_cookies()
|
self.web_view.clear_cache_and_cookies()
|
||||||
QTimer.singleShot(100, self._navigate_home)
|
QTimer.singleShot(100, self._navigate_home)
|
||||||
|
|
||||||
if language_changed:
|
if not restart_prompt_shown and branding_changed:
|
||||||
|
logger.info(
|
||||||
|
"Branding changed: %s → %s",
|
||||||
|
old_branding_id,
|
||||||
|
self.config.active_branding_id,
|
||||||
|
)
|
||||||
|
self._handle_branding_change_restart()
|
||||||
|
restart_prompt_shown = True
|
||||||
|
|
||||||
|
if not restart_prompt_shown and language_changed:
|
||||||
logger.info(f"Language changed: {old_language} → {self.config.language}")
|
logger.info(f"Language changed: {old_language} → {self.config.language}")
|
||||||
self._handle_language_change_restart()
|
self._handle_language_change_restart()
|
||||||
|
|
||||||
|
|
@ -2046,21 +2060,42 @@ class MainWindow(QMainWindow):
|
||||||
self.web_view.clear_cache_and_cookies()
|
self.web_view.clear_cache_and_cookies()
|
||||||
self._navigate_home()
|
self._navigate_home()
|
||||||
|
|
||||||
|
def _handle_branding_change_restart(self) -> None:
|
||||||
|
"""Handle branding change by prompting for an optional restart."""
|
||||||
|
self._show_restart_prompt(
|
||||||
|
title_key="dialog.branding_changed.title",
|
||||||
|
message_key="dialog.branding_changed.msg",
|
||||||
|
restart_now_key="dialog.branding_changed.restart_now",
|
||||||
|
restart_later_key="dialog.branding_changed.restart_later",
|
||||||
|
)
|
||||||
|
|
||||||
def _handle_language_change_restart(self) -> None:
|
def _handle_language_change_restart(self) -> None:
|
||||||
"""Handle language change by prompting for an optional restart."""
|
"""Handle language change by prompting for an optional restart."""
|
||||||
|
self._show_restart_prompt(
|
||||||
|
title_key="dialog.language_changed.title",
|
||||||
|
message_key="dialog.language_changed.msg",
|
||||||
|
restart_now_key="dialog.language_changed.restart_now",
|
||||||
|
restart_later_key="dialog.language_changed.restart_later",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _show_restart_prompt(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
title_key: str,
|
||||||
|
message_key: str,
|
||||||
|
restart_now_key: str,
|
||||||
|
restart_later_key: str,
|
||||||
|
) -> None:
|
||||||
|
"""Show a restart prompt for settings that require a full restart."""
|
||||||
from PySide6.QtWidgets import QMessageBox
|
from PySide6.QtWidgets import QMessageBox
|
||||||
|
|
||||||
msg = QMessageBox(self)
|
msg = QMessageBox(self)
|
||||||
msg.setWindowTitle(tr("dialog.language_changed.title"))
|
msg.setWindowTitle(tr(title_key))
|
||||||
msg.setIcon(QMessageBox.Icon.Information)
|
msg.setIcon(QMessageBox.Icon.Information)
|
||||||
msg.setText(tr("dialog.language_changed.msg"))
|
msg.setText(tr(message_key))
|
||||||
|
|
||||||
restart_now_btn = msg.addButton(
|
restart_now_btn = msg.addButton(tr(restart_now_key), QMessageBox.ButtonRole.AcceptRole)
|
||||||
tr("dialog.language_changed.restart_now"), QMessageBox.ButtonRole.AcceptRole
|
msg.addButton(tr(restart_later_key), QMessageBox.ButtonRole.RejectRole)
|
||||||
)
|
|
||||||
msg.addButton(
|
|
||||||
tr("dialog.language_changed.restart_later"), QMessageBox.ButtonRole.RejectRole
|
|
||||||
)
|
|
||||||
|
|
||||||
msg.exec()
|
msg.exec()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,14 @@ from webdrop_bridge.config import Config, ConfigurationError
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(autouse=True)
|
@pytest.fixture(autouse=True)
|
||||||
def clear_env():
|
def clear_env(tmp_path):
|
||||||
"""Clear environment variables before each test to avoid persistence."""
|
"""Clear environment variables before each test to avoid persistence."""
|
||||||
# Save current env
|
# Save current env
|
||||||
saved_env = os.environ.copy()
|
saved_env = os.environ.copy()
|
||||||
|
|
||||||
|
# Isolate runtime branding state from the developer machine
|
||||||
|
os.environ["WEBDROP_BRANDING_DIR"] = str(tmp_path / "branding")
|
||||||
|
|
||||||
# Clear relevant variables
|
# Clear relevant variables
|
||||||
for key in list(os.environ.keys()):
|
for key in list(os.environ.keys()):
|
||||||
if key.startswith(
|
if key.startswith(
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,25 @@ class TestMainWindowInitialization:
|
||||||
assert window.drag_interceptor is not None
|
assert window.drag_interceptor is not None
|
||||||
|
|
||||||
|
|
||||||
|
class TestSettingsRestartBehavior:
|
||||||
|
"""Test restart prompts for settings changes that require a restart."""
|
||||||
|
|
||||||
|
def test_branding_change_prompts_restart(self, qtbot, sample_config):
|
||||||
|
"""Changing the active branding should trigger the restart flow."""
|
||||||
|
window = MainWindow(sample_config)
|
||||||
|
qtbot.addWidget(window)
|
||||||
|
|
||||||
|
with patch.object(window, "_handle_branding_change_restart") as mock_restart:
|
||||||
|
with patch("webdrop_bridge.ui.settings_dialog.SettingsDialog") as mock_dialog_cls:
|
||||||
|
mock_dialog = mock_dialog_cls.return_value
|
||||||
|
mock_dialog.exec.side_effect = lambda: setattr(
|
||||||
|
window.config, "active_branding_id", "agravity"
|
||||||
|
)
|
||||||
|
window._show_settings_dialog()
|
||||||
|
|
||||||
|
mock_restart.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
class TestMainWindowDragIntegration:
|
class TestMainWindowDragIntegration:
|
||||||
"""Test drag-and-drop integration."""
|
"""Test drag-and-drop integration."""
|
||||||
|
|
||||||
|
|
@ -228,7 +247,6 @@ class TestMainWindowOpenWith:
|
||||||
else:
|
else:
|
||||||
raise AssertionError(f"Unexpected call #{call_count[0]} to subprocess.run")
|
raise AssertionError(f"Unexpected call #{call_count[0]} to subprocess.run")
|
||||||
|
|
||||||
|
|
||||||
with patch("webdrop_bridge.ui.main_window.sys.platform", "darwin"):
|
with patch("webdrop_bridge.ui.main_window.sys.platform", "darwin"):
|
||||||
with patch("webdrop_bridge.ui.main_window.subprocess.run", side_effect=mock_run):
|
with patch("webdrop_bridge.ui.main_window.subprocess.run", side_effect=mock_run):
|
||||||
assert window._open_with_app_chooser(str(test_file)) is True
|
assert window._open_with_app_chooser(str(test_file)) is True
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue