Allow changing the date when logging time (rather than having to go to that date before clicking on adding time log/opening time log manager)

This commit is contained in:
Miguel Jacq 2025-12-01 10:19:41 +11:00
parent 078f56a39b
commit 22b4cf4da7
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
6 changed files with 93 additions and 22 deletions

View file

@ -2,6 +2,7 @@
* Add + button to time log widget in side bar to have a simplified log entry dialog (without summary or report option)
* Allow click-and-drag mouse select on lines with checkbox, to capture the checkbox as well as the text.
* Allow changing the date when logging time (rather than having to go to that date before clicking on adding time log/opening time log manager)
# 0.5.4

View file

@ -236,6 +236,8 @@
"time_log": "Time log",
"time_log_collapsed_hint": "Time log",
"time_log_date_label": "Time log date: {date}",
"time_log_change_date": "Change date",
"time_log_select_date_title": "Select time log date",
"time_log_for": "Time log for {date}",
"time_log_no_date": "Time log",
"time_log_no_entries": "No time entries yet",

View file

@ -108,7 +108,7 @@ class MainWindow(QMainWindow):
self.search.resultDatesChanged.connect(self._on_search_dates_changed)
# Features
self.time_log = TimeLogWidget(self.db)
self.time_log = TimeLogWidget(self.db, themes=self.themes)
self.tags = PageTagsWidget(self.db)
self.tags.tagActivated.connect(self._on_tag_activated)
@ -342,7 +342,6 @@ class MainWindow(QMainWindow):
# re-apply all runtime color tweaks when theme changes
self.themes.themeChanged.connect(lambda _t: self._retheme_overrides())
self._apply_calendar_text_colors()
# apply once on startup so links / calendar colors are set immediately
self._retheme_overrides()
@ -1020,22 +1019,10 @@ class MainWindow(QMainWindow):
save_db_config(cfg)
def _retheme_overrides(self):
self._apply_calendar_text_colors()
self._apply_search_highlights(getattr(self, "_search_highlighted_dates", set()))
self.calendar.update()
self.editor.viewport().update()
def _apply_calendar_text_colors(self):
pal = QApplication.instance().palette()
txt = pal.windowText().color()
fmt = QTextCharFormat()
fmt.setForeground(txt)
# Use normal text color for weekends
self.calendar.setWeekdayTextFormat(Qt.Saturday, fmt)
self.calendar.setWeekdayTextFormat(Qt.Sunday, fmt)
# --------------- Search sidebar/results helpers ---------------- #
def _on_search_dates_changed(self, date_strs: list[str]):

View file

@ -137,7 +137,9 @@ class PomodoroManager:
hours = 0.25
# Open time log dialog
dlg = TimeLogDialog(self._db, date_iso, self._parent, True)
dlg = TimeLogDialog(
self._db, date_iso, self._parent, True, themes=self._parent.themes
)
# Pre-fill the hours
dlg.hours_spin.setValue(hours)

View file

@ -1,9 +1,9 @@
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from PySide6.QtGui import QPalette, QColor, QGuiApplication
from PySide6.QtGui import QPalette, QColor, QGuiApplication, QTextCharFormat
from PySide6.QtWidgets import QApplication, QCalendarWidget, QWidget
from PySide6.QtCore import QObject, Signal
from PySide6.QtCore import QObject, Signal, Qt
from weakref import WeakSet
@ -174,6 +174,14 @@ class ThemeManager(QObject):
cal.setPalette(app_pal)
cal.setStyleSheet("")
# --- Normalise weekend colours on *all* themed calendars -------------
# Qt's default is red for weekends; we want them to match normal text.
weekday_color = app_pal.windowText().color()
weekend_fmt = QTextCharFormat()
weekend_fmt.setForeground(weekday_color)
cal.setWeekdayTextFormat(Qt.Saturday, weekend_fmt)
cal.setWeekdayTextFormat(Qt.Sunday, weekend_fmt)
cal.update()
def _calendar_qss(self, highlight_css: str) -> str:

View file

@ -11,7 +11,9 @@ from PySide6.QtCore import Qt, QDate, QUrl
from PySide6.QtGui import QPainter, QColor, QImage, QTextDocument, QPageLayout
from PySide6.QtPrintSupport import QPrinter
from PySide6.QtWidgets import (
QCalendarWidget,
QDialog,
QDialogButtonBox,
QFrame,
QVBoxLayout,
QHBoxLayout,
@ -40,6 +42,7 @@ from PySide6.QtWidgets import (
)
from .db import DBManager
from .theme import ThemeManager
from . import strings
@ -49,9 +52,15 @@ class TimeLogWidget(QFrame):
Shown in the left sidebar above the Tags widget.
"""
def __init__(self, db: DBManager, parent: QWidget | None = None):
def __init__(
self,
db: DBManager,
themes: ThemeManager | None = None,
parent: QWidget | None = None,
):
super().__init__(parent)
self._db = db
self._themes = themes
self._current_date: Optional[str] = None
self.setFrameShape(QFrame.StyledPanel)
@ -162,7 +171,7 @@ class TimeLogWidget(QFrame):
if not self._current_date:
return
dlg = TimeLogDialog(self._db, self._current_date, self)
dlg = TimeLogDialog(self._db, self._current_date, self, themes=self._themes)
dlg.exec()
# Always refresh summary + header totals
@ -175,7 +184,9 @@ class TimeLogWidget(QFrame):
if not self._current_date:
return
dlg = TimeLogDialog(self._db, self._current_date, self, True)
dlg = TimeLogDialog(
self._db, self._current_date, self, True, themes=self._themes
)
dlg.exec()
# Always refresh summary + header totals
@ -202,9 +213,11 @@ class TimeLogDialog(QDialog):
date_iso: str,
parent=None,
log_entry_only: bool | None = False,
themes: ThemeManager | None = None,
):
super().__init__(parent)
self._db = db
self._themes = themes
self._date_iso = date_iso
self._current_entry_id: Optional[int] = None
# Guard flag used when repopulating the table so we dont treat
@ -216,8 +229,20 @@ class TimeLogDialog(QDialog):
root = QVBoxLayout(self)
# --- Top: date label
root.addWidget(QLabel(strings._("time_log_date_label").format(date=date_iso)))
# --- Top: date label + change-date button
date_row = QHBoxLayout()
self.date_label = QLabel(strings._("time_log_date_label").format(date=date_iso))
date_row.addWidget(self.date_label)
date_row.addStretch(1)
# You can i18n this later if you like
self.change_date_btn = QPushButton(strings._("time_log_change_date"))
self.change_date_btn.clicked.connect(self._on_change_date_clicked)
date_row.addWidget(self.change_date_btn)
root.addLayout(date_row)
# --- Project / activity / hours row
form = QFormLayout()
@ -370,6 +395,52 @@ class TimeLogDialog(QDialog):
# ----- Actions -----------------------------------------------------
def _on_change_date_clicked(self) -> None:
"""Let the user choose a different date and reload entries."""
# Start from current dialog date; fall back to today if invalid
current_qdate = QDate.fromString(self._date_iso, Qt.ISODate)
if not current_qdate.isValid():
current_qdate = QDate.currentDate()
dlg = QDialog(self)
dlg.setWindowTitle(strings._("time_log_select_date_title"))
layout = QVBoxLayout(dlg)
calendar = QCalendarWidget(dlg)
calendar.setSelectedDate(current_qdate)
layout.addWidget(calendar)
# Apply the same theming as the main sidebar calendar
if self._themes is not None:
self._themes.register_calendar(calendar)
buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel, parent=dlg
)
buttons.accepted.connect(dlg.accept)
buttons.rejected.connect(dlg.reject)
layout.addWidget(buttons)
if dlg.exec() != QDialog.Accepted:
return
new_qdate = calendar.selectedDate()
new_iso = new_qdate.toString(Qt.ISODate)
if new_iso == self._date_iso:
# No change
return
# Update state
self._date_iso = new_iso
# Update window title and header label
self.setWindowTitle(strings._("time_log_for").format(date=new_iso))
self.date_label.setText(strings._("time_log_date_label").format(date=new_iso))
# Reload entries for the newly selected date
self._reload_entries()
def _ensure_project_id(self) -> Optional[int]:
"""Get selected project_id from combo."""
idx = self.project_combo.currentIndex()