feat(projects/khora): group calendars by account

Derive account groups from khal calendar paths and place grouped calendar controls in a scrollable sidebar region.

Assisted-by: pi (gpt-5.6-sol)
This commit is contained in:
Gabriel Fontes
2026-08-15 15:52:57 -03:00
parent 8405980567
commit cf586aa7d4
4 changed files with 58 additions and 11 deletions
+1
View File
@@ -23,6 +23,7 @@ class KhalRepository:
name=name,
color=settings.get("color") or None,
readonly=settings.get("readonly", False),
account=Path(settings["path"]).expanduser().parent.name or "Calendars",
)
for name, settings in self._config["calendars"].items()
if settings.get("type", "calendar") == "calendar"
+1
View File
@@ -59,6 +59,7 @@ class Calendar:
name: str
color: str | None = None
readonly: bool = False
account: str = "Calendars"
@dataclass(frozen=True)
+32 -11
View File
@@ -10,7 +10,7 @@ from gi.repository import Adw, Gio, GLib, Gtk, Pango
from .colors import display_color
from .khal_adapter import KhalRepository
from .model import Event, event_slot_range, period_label, shifted_date, week_dates
from .model import Calendar, Event, event_slot_range, period_label, shifted_date, week_dates
SIDEBAR_WIDTH = 280
@@ -130,20 +130,41 @@ class KhoraWindow(Adw.ApplicationWindow):
box.append(self._calendar)
box.append(Gtk.Label(label="Calendars", xalign=0, css_classes=["heading"]))
calendars = Gtk.ListBox(selection_mode=Gtk.SelectionMode.NONE)
calendars.add_css_class("boxed-list")
groups = Gtk.Box(
orientation=Gtk.Orientation.VERTICAL,
spacing=18,
margin_bottom=6,
)
assert self._repository is not None
calendars_by_account: dict[str, list[Calendar]] = {}
for calendar in self._repository.calendars:
toggle = Gtk.Switch(active=True, valign=Gtk.Align.CENTER)
toggle.connect("notify::active", self._on_calendar_toggled, calendar.name)
row = Adw.ActionRow(title=calendar.name, activatable=True)
row.add_prefix(self._color_dot(calendar.color))
row.add_suffix(toggle)
row.set_activatable_widget(toggle)
calendars.append(row)
box.append(calendars)
calendars_by_account.setdefault(calendar.account, []).append(calendar)
for account, calendars in calendars_by_account.items():
group = Adw.PreferencesGroup(title=self._account_label(account))
for calendar in calendars:
toggle = Gtk.Switch(active=True, valign=Gtk.Align.CENTER)
toggle.connect("notify::active", self._on_calendar_toggled, calendar.name)
row = Adw.ActionRow(title=calendar.name, activatable=True)
row.add_prefix(self._color_dot(calendar.color))
row.add_suffix(toggle)
row.set_activatable_widget(toggle)
group.add(row)
groups.append(group)
box.append(
Gtk.ScrolledWindow(
child=groups,
hscrollbar_policy=Gtk.PolicyType.NEVER,
vexpand=True,
)
)
return box
@staticmethod
def _account_label(account: str) -> str:
return account.replace("-", " ").replace("_", " ").title()
def _build_calendar_view(self) -> Gtk.Widget:
overlay = Gtk.Overlay()
scroller = Gtk.ScrolledWindow(
+24
View File
@@ -0,0 +1,24 @@
from khora.khal_adapter import KhalRepository
def test_calendar_accounts_come_from_their_parent_directory() -> None:
repository = KhalRepository.__new__(KhalRepository)
repository._config = {
"calendars": {
"Personal": {
"path": "/home/example/Calendars/personal/default",
"type": "calendar",
"color": "dark blue",
"readonly": False,
},
"University": {
"path": "/home/example/Calendars/university/classes",
"type": "calendar",
"readonly": True,
},
}
}
calendars = repository.calendars
assert tuple(calendar.account for calendar in calendars) == ("personal", "university")