Pomodoro timer is now in the sidebar when toggled on, rather than as a separate dialog, so it stays out of the way

This commit is contained in:
Miguel Jacq 2025-12-03 17:19:30 +11:00
parent 8823a304cf
commit b06f213522
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
6 changed files with 196 additions and 62 deletions

View file

@ -1194,22 +1194,30 @@ class MainWindow(QMainWindow):
self.upcoming_reminders._add_reminder()
def _on_timer_requested(self):
"""Start a Pomodoro timer for the current line."""
editor = getattr(self, "editor", None)
if editor is None:
return
"""Toggle the embedded Pomodoro timer for the current line."""
action = self.toolBar.actTimer
# Get the current line text
line_text = editor.get_current_line_task_text()
# Turned on -> start a new timer for the current line
if action.isChecked():
editor = getattr(self, "editor", None)
if editor is None:
# No editor; immediately reset the toggle
action.setChecked(False)
return
if not line_text:
line_text = strings._("pomodoro_time_log_default_text")
# Get the current line text
line_text = editor.get_current_line_task_text()
if not line_text:
line_text = strings._("pomodoro_time_log_default_text")
# Get current date
date_iso = self.editor.current_date.toString("yyyy-MM-dd")
# Get current date
date_iso = self.editor.current_date.toString("yyyy-MM-dd")
# Start the timer
self.pomodoro_manager.start_timer_for_line(line_text, date_iso)
# Start the timer embedded in the sidebar
self.pomodoro_manager.start_timer_for_line(line_text, date_iso)
else:
# Turned off -> cancel any running timer and remove the widget
self.pomodoro_manager.cancel_timer()
def _show_flashing_reminder(self, text: str):
"""

View file

@ -3,9 +3,9 @@ from __future__ import annotations
import math
from typing import Optional
from PySide6.QtCore import Qt, QTimer, Signal, Slot
from PySide6.QtCore import Qt, QTimer, Signal, Slot, QSignalBlocker
from PySide6.QtWidgets import (
QDialog,
QFrame,
QVBoxLayout,
QHBoxLayout,
QLabel,
@ -18,16 +18,13 @@ from .db import DBManager
from .time_log import TimeLogDialog
class PomodoroTimer(QDialog):
"""A simple timer dialog for tracking work time on a specific task."""
class PomodoroTimer(QFrame):
"""A simple timer for tracking work time on a specific task."""
timerStopped = Signal(int, str) # Emits (elapsed_seconds, task_text)
def __init__(self, task_text: str, parent: Optional[QWidget] = None):
super().__init__(parent)
self.setWindowTitle(strings._("toolbar_pomodoro_timer"))
self.setModal(False)
self.setMinimumWidth(300)
self._task_text = task_text
self._elapsed_seconds = 0
@ -43,7 +40,7 @@ class PomodoroTimer(QDialog):
# Timer display
self.time_label = QLabel("00:00:00")
font = self.time_label.font()
font.setPointSize(24)
font.setPointSize(20)
font.setBold(True)
self.time_label.setFont(font)
self.time_label.setAlignment(Qt.AlignCenter)
@ -103,7 +100,7 @@ class PomodoroTimer(QDialog):
self._timer.stop()
self.timerStopped.emit(self._elapsed_seconds, self._task_text)
self.accept()
self.close()
class PomodoroManager:
@ -115,17 +112,47 @@ class PomodoroManager:
self._active_timer: Optional[PomodoroTimer] = None
def start_timer_for_line(self, line_text: str, date_iso: str):
"""Start a new timer for the given line of text."""
# Stop any existing timer
if self._active_timer and self._active_timer.isVisible():
self._active_timer.close()
"""
Start a new timer for the given line of text and embed it into the
TimeLogWidget in the main window sidebar.
"""
# Cancel any existing timer first
self.cancel_timer()
# Create new timer
self._active_timer = PomodoroTimer(line_text, self._parent)
# The timer lives inside the TimeLogWidget in the sidebar
time_log_widget = getattr(self._parent, "time_log", None)
if time_log_widget is None:
return
self._active_timer = PomodoroTimer(line_text, time_log_widget)
self._active_timer.timerStopped.connect(
lambda seconds, text: self._on_timer_stopped(seconds, text, date_iso)
)
self._active_timer.show()
# Ask the TimeLogWidget to own and display the widget
if hasattr(time_log_widget, "show_pomodoro_widget"):
time_log_widget.show_pomodoro_widget(self._active_timer)
else:
# Fallback just attach it as a child widget
self._active_timer.setParent(time_log_widget)
self._active_timer.show()
def cancel_timer(self):
"""Cancel any running timer without logging and remove it from the sidebar."""
if not self._active_timer:
return
time_log_widget = getattr(self._parent, "time_log", None)
if time_log_widget is not None and hasattr(
time_log_widget, "clear_pomodoro_widget"
):
time_log_widget.clear_pomodoro_widget()
else:
# Fallback if the widget API doesn't exist
self._active_timer.setParent(None)
self._active_timer.deleteLater()
self._active_timer = None
def _on_timer_stopped(self, elapsed_seconds: int, task_text: str, date_iso: str):
"""Handle timer stop - open time log dialog with pre-filled data."""
@ -137,6 +164,16 @@ class PomodoroManager:
if hours < 0.25:
hours = 0.25
# Untoggle the toolbar button without retriggering the slot
tool_bar = getattr(self._parent, "toolBar", None)
if tool_bar is not None and hasattr(tool_bar, "actTimer"):
blocker = QSignalBlocker(tool_bar.actTimer)
tool_bar.actTimer.setChecked(False)
del blocker
# Remove the embedded widget
self.cancel_timer()
# Open time log dialog
dlg = TimeLogDialog(
self._db,
@ -155,3 +192,13 @@ class PomodoroManager:
# Show the dialog
dlg.exec()
time_log_widget = getattr(self._parent, "time_log", None)
if time_log_widget is not None:
# Same behaviour as TimeLogWidget._open_dialog/_open_dialog_log_only:
# reload the summary so the TimeLogWidget in sidebar updates its totals
time_log_widget._reload_summary()
if not time_log_widget.toggle_btn.isChecked():
time_log_widget.summary_label.setText(
strings._("time_log_collapsed_hint")
)

View file

@ -106,6 +106,8 @@ class TimeLogWidget(QFrame):
self.summary_label = QLabel(strings._("time_log_no_entries"))
self.summary_label.setWordWrap(True)
self.body_layout.addWidget(self.summary_label)
# Optional embedded Pomodoro timer widget lives underneath the summary.
self._pomodoro_widget: Optional[QWidget] = None
self.body.setVisible(False)
main = QVBoxLayout(self)
@ -121,6 +123,30 @@ class TimeLogWidget(QFrame):
if not self.toggle_btn.isChecked():
self.summary_label.setText(strings._("time_log_collapsed_hint"))
def show_pomodoro_widget(self, widget: QWidget) -> None:
"""Embed Pomodoro timer widget in the body area."""
if self._pomodoro_widget is not None:
self.body_layout.removeWidget(self._pomodoro_widget)
self._pomodoro_widget.deleteLater()
self._pomodoro_widget = widget
self.body_layout.addWidget(widget)
widget.show()
# Ensure the body is visible so the timer is obvious
self.body.setVisible(True)
self.toggle_btn.setChecked(True)
self.toggle_btn.setArrowType(Qt.DownArrow)
def clear_pomodoro_widget(self) -> None:
"""Remove any embedded Pomodoro timer widget."""
if self._pomodoro_widget is None:
return
self.body_layout.removeWidget(self._pomodoro_widget)
self._pomodoro_widget.deleteLater()
self._pomodoro_widget = None
# ----- internals ---------------------------------------------------
def _on_toggle(self, checked: bool) -> None:

View file

@ -119,6 +119,7 @@ class ToolBar(QToolBar):
# Focus timer
self.actTimer = QAction("", self)
self.actTimer.setToolTip(strings._("toolbar_pomodoro_timer"))
self.actTimer.setCheckable(True)
self.actTimer.triggered.connect(self.timerRequested)
# Documents