fix timers
lint / ruff (push) Failing after 15s
tests / desktop (push) Successful in 21s
tests / web (push) Successful in 46s
docker / image (push) Failing after 1m31s
tests / android-core (push) Successful in 1m5s
tests / backend (push) Successful in 2m33s
android / apk (push) Successful in 4m34s

This commit is contained in:
timka123 committed 2026-10-27 18:52:54 +03:00
1 parent ff77d8f89f
commit 157a113c39
30 files changed
+3331 -419

No files matched your search

+30 -7
View File
@@ -78,7 +78,17 @@ class Controller(QObject):
self._last_session_id: int | None = None
self._last_kind = ""
self._last_status = ""
self._completing = False
self._completed_id: int | None = None
"""The interval we have already asked the server to finish.
An id rather than a bare "in flight" flag. A poll issued just before the
countdown ran out answers with that interval still running at 00:00, and
a flag cleared by that answer sends `complete` a second time — onto the
break `auto_next` has since started, which is why a break could end the
instant it began. Ids are never reused, so the second attempt is never
made. Cleared only when the call itself fails, so a refused or dropped
complete is still retried.
"""
self._paused_by_lock = False
self._mini_visible = False
self._mini_dismissed = False
@@ -174,6 +184,13 @@ class Controller(QObject):
current = self._state.get("current")
return str(current["status"]) if current else "idle"
@property
def _session_id(self) -> int | None:
"""The running interval's id, or None when nothing is running."""
current = self._state.get("current") or {}
session_id = current.get("id")
return int(session_id) if session_id is not None else None
@pyqtProperty(int, notify=stateChanged)
def remainingSeconds(self) -> int:
if self._state.get("current"):
@@ -393,7 +410,7 @@ class Controller(QObject):
@pyqtSlot()
def complete(self) -> None:
self._send("complete", {"auto_next": True})
self._send("complete", {"auto_next": True, "session_id": self._session_id})
@pyqtSlot()
@pyqtSlot(str)
@@ -567,7 +584,6 @@ class Controller(QObject):
self._last_session_id = session_id
self._last_kind = kind
self._last_status = status
self._completing = False
self.stateChanged.emit()
self._update_launcher()
@@ -610,12 +626,18 @@ class Controller(QObject):
def _on_command_failed(self, name: str, detail: str) -> None:
log.warning("%s failed: %s", name, detail)
if name == "complete":
# It never landed, so the interval at 00:00 is still owed a complete.
self._completed_id = None
self.toast.emit(detail)
def _on_command_done(self, name: str, result: dict[str, Any]) -> None:
if name == "complete":
finished = result.get("finished") or {}
self._announce_finished(str(finished.get("kind", "work")), result)
finished = result.get("finished")
# None means the server declined: something else was running by the
# time the call arrived, so nothing finished and nothing is announced.
if finished:
self._announce_finished(str(finished.get("kind", "work")), result)
elif name == "send_report":
self.toast.emit("Daily report sent" if result.get("sent") else "Report not sent — check Telegram settings")
elif name == "refresh_sources":
@@ -706,10 +728,11 @@ class Controller(QObject):
if self._remaining % 5 == 0:
self._update_launcher()
return
if not self._completing:
session_id = self._session_id
if session_id is not None and self._completed_id != session_id:
# The countdown reached zero: the server books the interval, and its
# reply decides what happens next (auto-break, or nothing).
self._completing = True
self._completed_id = session_id
self.complete()
def _check_idle(self) -> None: