diff --git a/CHANGELOG.md b/CHANGELOG.md index e8f9317..bf757e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Änderungsprotokoll +## 1.0.11 – 2026-09-27 + +### Behoben + +- Der Button „Pausieren“ ist im Leerlauf deaktiviert, damit SyncVito nicht versehentlich ohne aktive Aufgabe in den Pausenzustand versetzt werden kann. +- Beim Klick auf „Alle jetzt synchronisieren“ oder „Auswahl synchronisieren“ wird ein eventuell aktiver Pausenzustand automatisch aufgehoben und der Lauf sofort gestartet. +- Klickt man auf „Fortsetzen“, wenn zuvor noch keine Aufgabe eingereiht war, startet SyncVito direkt alle aktiven Aufgaben, statt wirkungslos zu bleiben. +- Die automatische Hintergrund-Updateprüfung setzt die Fortschrittsleiste im Leerlauf nicht mehr dauerhaft auf 100 % mit „SyncVito ist aktuell“, sondern die Leiste bleibt ordnungsgemäß auf „Bereit“. +- Die Tray-Benachrichtigung beim Schließen des Fensters lautet nun unmissverständlich „SyncVito minimiert“ statt „SyncVito läuft weiter“. + ## 1.0.10 – 2026-09-27 ### Neu diff --git a/pyproject.toml b/pyproject.toml index 71b5009..6d7359f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "syncvito" -version = "1.0.10" +version = "1.0.11" description = "Windows-Desktopwerkzeug für lokale und NAS-Synchronisation" readme = "README.md" requires-python = ">=3.11" diff --git a/src/syncvito/coordinator.py b/src/syncvito/coordinator.py index 12386f0..cda8176 100644 --- a/src/syncvito/coordinator.py +++ b/src/syncvito/coordinator.py @@ -194,6 +194,8 @@ class SyncCoordinator(QObject): def enqueue_all(self) -> None: """Stellt alle aktiven Aufgaben zur manuellen Ausführung an.""" + if self.config.settings.paused: + self.set_paused(False) for task in self.config.tasks: if task.enabled: self.enqueue(task.id) @@ -213,6 +215,10 @@ class SyncCoordinator(QObject): for tid in self.config.settings.pending_queue: if tid not in self._queue and any(t.id == tid and t.enabled for t in self.config.tasks): self._queue.append(tid) + if not self._queue and not self._running_task_id: + for task in self.config.tasks: + if task.enabled: + self._queue.append(task.id) self._start_next() with suppress(Exception): self.config_store.save(self.config) diff --git a/src/syncvito/main_window.py b/src/syncvito/main_window.py index 463f0bb..0d0ad90 100644 --- a/src/syncvito/main_window.py +++ b/src/syncvito/main_window.py @@ -140,8 +140,8 @@ class MainWindow(QMainWindow): event.ignore() self.hide() self.tray.showMessage( - "SyncVito läuft weiter", - "Das Fenster wurde in den Infobereich verschoben.", + "SyncVito minimiert", + "SyncVito bleibt im Infobereich aktiv.", QSystemTrayIcon.MessageIcon.Information, 2500, ) @@ -572,6 +572,8 @@ class MainWindow(QMainWindow): if task is None: QMessageBox.information(self, "Keine Auswahl", "Bitte zuerst eine Aufgabe auswählen.") return + if self.config.settings.paused: + self.coordinator.set_paused(False) self.coordinator.enqueue(task.id) def _persist_tasks(self, message: str) -> None: @@ -652,10 +654,18 @@ class MainWindow(QMainWindow): self._mark_update_checked() self._set_update_indicator(None) self._notified_update_version = None - self._update_progress(100, "SyncVito ist aktuell") self._append_log("Update", "Erfolg", "Die installierte Version ist aktuell.") if manual: + self._update_progress(100, "SyncVito ist aktuell") QMessageBox.information(self, "Keine Updates", "Du verwendest bereits die aktuelle SyncVito-Version.") + elif not self.coordinator.is_running: + self.progress_text.setText("SyncVito ist aktuell") + QTimer.singleShot(3000, self._reset_idle_progress) + + def _reset_idle_progress(self) -> None: + if not self.coordinator.is_running and not self.config.settings.paused: + self.progress_text.setText("Bereit") + self.progress_bar.setValue(0) def _on_update_error(self, message: str, manual: bool) -> None: self._update_progress(0, "Updateprüfung fehlgeschlagen") @@ -740,18 +750,32 @@ class MainWindow(QMainWindow): def _update_pause_action(self) -> None: is_paused = self.config.settings.paused + is_running = self.coordinator.is_running + has_queue = bool(self.coordinator.queued_task_ids) + if is_paused: btn_text = "▶ Fortsetzen" tray_text = "Fortsetzen" - else: - btn_text = "⏸ Pausieren" if self.coordinator.is_running else "Pausieren" + btn_enabled = True + primary = True + elif is_running or has_queue: + btn_text = "⏸ Pausieren" tray_text = "Pausieren" + btn_enabled = True + primary = False + else: + btn_text = "Pausieren" + tray_text = "Pausieren" + btn_enabled = False + primary = False self.pause_action.setText(tray_text) + self.pause_action.setEnabled(btn_enabled) for btn in (getattr(self, "header_pause_button", None), getattr(self, "dock_pause_button", None)): if btn is not None: btn.setText(btn_text) - btn.setProperty("primary", is_paused) + btn.setEnabled(btn_enabled) + btn.setProperty("primary", primary) btn.style().unpolish(btn) btn.style().polish(btn) diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index b7f7271..bb809aa 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -137,3 +137,17 @@ def test_stop_persists_running_task_and_queue_for_restart(coordinator: SyncCoord assert coordinator.config.settings.paused is True assert coordinator.config.settings.pending_queue == [task1.id, task2.id] + + +def test_enqueue_all_unpauses_and_runs(coordinator: SyncCoordinator) -> None: + from types import SimpleNamespace + + coordinator.set_paused(True) + workers = [] + coordinator.pool = SimpleNamespace(start=workers.append) + + coordinator.enqueue_all() + + assert not coordinator.config.settings.paused + assert len(workers) == 1 + assert coordinator.running_task_id == coordinator.config.tasks[0].id diff --git a/version.txt b/version.txt index 7ee7020..59e9e60 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.0.10 +1.0.11