Add option to automatically move yesterday's unchecked TODOs to today on startup

This commit is contained in:
Miguel Jacq 2025-11-06 15:45:31 +11:00
parent f7903c2cd9
commit 58f4f0a0b5
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
8 changed files with 99 additions and 4 deletions

View file

@ -6,6 +6,7 @@
* Represent in the History diff pane when an image was the thing that changed
* Support theme choice in settings (light/dark/system)
* Add Checkboxes in the editor. Typing 'TODO' at the start of a line will auto-convert into a checkbox.
* Add option to automatically move yesterday's unchecked TODOs to today on startup
# 0.1.9

View file

@ -20,6 +20,7 @@ class DBConfig:
key: str
idle_minutes: int = 15 # 0 = never lock
theme: str = "system"
move_todos: bool = False
class DBManager:

View file

@ -886,5 +886,12 @@ class Editor(QTextEdit):
def setHtml(self, html: str) -> None:
super().setHtml(html)
doc = self.document()
block = doc.firstBlock()
while block.isValid():
self._style_checkbox_glyph(block) # Apply checkbox styling to each block
block = block.next()
# Ensure anchors adopt the palette color on startup
self._retint_anchors_to_palette()

View file

@ -3,6 +3,7 @@ from __future__ import annotations
import datetime
import os
import sys
import re
from pathlib import Path
from PySide6.QtCore import (
@ -224,7 +225,8 @@ class MainWindow(QMainWindow):
self.editor.textChanged.connect(self._on_text_changed)
# First load + mark dates in calendar with content
self._load_selected_date()
if not self._load_yesterday_todos():
self._load_selected_date()
self._refresh_calendar_marks()
# Restore window position from settings
@ -469,17 +471,31 @@ class MainWindow(QMainWindow):
d = self.calendar.selectedDate()
return f"{d.year():04d}-{d.month():02d}-{d.day():02d}"
def _load_selected_date(self, date_iso=False):
def _load_selected_date(self, date_iso=False, extra_data=False):
if not date_iso:
date_iso = self._current_date_iso()
try:
text = self.db.get_entry(date_iso)
if extra_data:
# Wrap extra_data in a <p> tag for HTML rendering
extra_data_html = f"<p>{extra_data}</p>"
# Inject the extra_data before the closing </body></html>
modified = re.sub(r"(<\/body><\/html>)", extra_data_html + r"\1", text)
text = modified
self.editor.setHtml(text)
self._dirty = True
self._save_date(date_iso, True)
print("end")
except Exception as e:
QMessageBox.critical(self, "Read Error", str(e))
return
self.editor.blockSignals(True)
self.editor.setHtml(text)
self.editor.blockSignals(False)
self._dirty = False
# track which date the editor currently represents
self._active_date_iso = date_iso
@ -500,6 +516,56 @@ class MainWindow(QMainWindow):
today = QDate.currentDate()
self.calendar.setSelectedDate(today)
def _load_yesterday_todos(self):
try:
if not self.cfg.move_todos:
return
yesterday_str = QDate.currentDate().addDays(-1).toString("yyyy-MM-dd")
text = self.db.get_entry(yesterday_str)
unchecked_items = []
# Regex to match the unchecked checkboxes and their associated text
checkbox_pattern = re.compile(
r"<span[^>]*>(☐)</span>\s*(.*?)</p>", re.DOTALL
)
# Find unchecked items and store them
for match in checkbox_pattern.finditer(text):
checkbox = match.group(1) # Either ☐ or ☑
item_text = match.group(2).strip() # The text after the checkbox
if checkbox == "": # If it's an unchecked checkbox (☐)
unchecked_items.append("" + item_text) # Store the unchecked item
# Remove the unchecked items from yesterday's HTML content
if unchecked_items:
# This regex will find the entire checkbox line and remove it from the HTML content
uncheckbox_pattern = re.compile(
r"<span[^>]*>☐</span>\s*(.*?)</p>", re.DOTALL
)
modified_text = re.sub(
uncheckbox_pattern, "", text
) # Remove the checkbox lines
# Save the modified HTML back to the database
self.db.save_new_version(
yesterday_str,
modified_text,
"Unchecked checkbox items moved to next day",
)
# Join unchecked items into a formatted string
unchecked_str = "\n".join(
[f"<p>{item}</p>" for item in unchecked_items]
)
# Load the unchecked items into the current editor
self._load_selected_date(False, unchecked_str)
else:
return False
except Exception as e:
raise SystemError(e)
def _on_date_changed(self):
"""
When the calendar selection changes, save the previous day's note if dirty,
@ -592,6 +658,7 @@ class MainWindow(QMainWindow):
self.cfg.key = new_cfg.key
self.cfg.idle_minutes = getattr(new_cfg, "idle_minutes", self.cfg.idle_minutes)
self.cfg.theme = getattr(new_cfg, "theme", self.cfg.theme)
self.cfg.move_todos = getattr(new_cfg, "move_todos", self.cfg.move_todos)
# Persist once
save_db_config(self.cfg)

View file

@ -24,7 +24,10 @@ def load_db_config() -> DBConfig:
key = s.value("db/key", "")
idle = s.value("ui/idle_minutes", 15, type=int)
theme = s.value("ui/theme", "system", type=str)
return DBConfig(path=path, key=key, idle_minutes=idle, theme=theme)
move_todos = s.value("ui/move_todos", False, type=bool)
return DBConfig(
path=path, key=key, idle_minutes=idle, theme=theme, move_todos=move_todos
)
def save_db_config(cfg: DBConfig) -> None:
@ -33,3 +36,4 @@ def save_db_config(cfg: DBConfig) -> None:
s.setValue("db/key", str(cfg.key))
s.setValue("ui/idle_minutes", str(cfg.idle_minutes))
s.setValue("ui/theme", str(cfg.theme))
s.setValue("ui/move_todos", str(cfg.move_todos))

View file

@ -69,6 +69,19 @@ class SettingsDialog(QDialog):
form.addRow(theme_group)
# Add Behaviour
behaviour_group = QGroupBox("Behaviour")
behaviour_layout = QVBoxLayout(behaviour_group)
self.move_todos = QCheckBox(
"Move yesterday's unchecked TODOs to today on startup"
)
self.move_todos.setChecked(current_settings.move_todos)
self.move_todos.setCursor(Qt.PointingHandCursor)
behaviour_layout.addWidget(self.move_todos)
form.addRow(behaviour_group)
self.path_edit = QLineEdit(str(self._cfg.path))
self.path_edit.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
browse_btn = QPushButton("Browse…")
@ -223,11 +236,13 @@ class SettingsDialog(QDialog):
selected_theme = Theme.SYSTEM
key_to_save = self.key if self.save_key_btn.isChecked() else ""
self._cfg = DBConfig(
path=Path(self.path_edit.text()),
key=key_to_save,
idle_minutes=self.idle_spin.value(),
theme=selected_theme.value,
move_todos=self.move_todos.isChecked(),
)
save_db_config(self._cfg)

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "bouquin"
version = "0.1.9"
version = "0.1.10"
description = "Bouquin is a simple, opinionated notebook application written in Python, PyQt and SQLCipher."
authors = ["Miguel Jacq <mig@mig5.net>"]
readme = "README.md"

0
tests.sh Normal file → Executable file
View file