mirror of
https://github.com/Misterio77/Foundry.git
synced 2026-08-24 02:14:13 -05:00
fix(projects/khora): use calendar colors for events
Color day and week event cards with their calendar color and choose a contrasting foreground instead of showing only a colored marker. Assisted-by: pi (gpt-5.6-sol)
This commit is contained in:
@@ -61,6 +61,20 @@ def display_color(value: str | None) -> str:
|
||||
return _DEFAULT
|
||||
|
||||
|
||||
def contrasting_foreground(value: str | None) -> str:
|
||||
"""Choose black or white for readable text over a calendar color."""
|
||||
color = display_color(value).lstrip("#")
|
||||
if len(color) == 3:
|
||||
color = "".join(channel * 2 for channel in color)
|
||||
red, green, blue = (int(color[index : index + 2], 16) / 255 for index in (0, 2, 4))
|
||||
|
||||
def linear(channel: float) -> float:
|
||||
return channel / 12.92 if channel <= 0.04045 else ((channel + 0.055) / 1.055) ** 2.4
|
||||
|
||||
luminance = 0.2126 * linear(red) + 0.7152 * linear(green) + 0.0722 * linear(blue)
|
||||
return "#000000" if luminance > 0.179 else "#ffffff"
|
||||
|
||||
|
||||
def _xterm_color(index: int) -> str:
|
||||
if index < 16:
|
||||
return _ANSI[index]
|
||||
|
||||
@@ -8,7 +8,7 @@ gi.require_version("Adw", "1")
|
||||
gi.require_version("Gtk", "4.0")
|
||||
from gi.repository import Adw, Gio, GLib, Gtk, Pango
|
||||
|
||||
from .colors import display_color
|
||||
from .colors import contrasting_foreground, display_color
|
||||
from .khal_adapter import KhalRepository
|
||||
from .model import Calendar, Event, event_slot_range, period_label, shifted_date, week_dates
|
||||
|
||||
@@ -40,6 +40,7 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
|
||||
assert repository is not None
|
||||
self._visible_calendars = {calendar.name for calendar in repository.calendars}
|
||||
self._event_color_providers: dict[str, Gtk.CssProvider] = {}
|
||||
self._view_content = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
|
||||
self._time_indicator: Gtk.Widget | None = None
|
||||
self._rendered_today = dt.date.today()
|
||||
@@ -293,7 +294,7 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
xalign=0,
|
||||
ellipsize=Pango.EllipsizeMode.END,
|
||||
tooltip_text=event.summary,
|
||||
css_classes=["all-day-event"],
|
||||
css_classes=["all-day-event", self._event_color_class(event.color)],
|
||||
)
|
||||
box.append(event_label)
|
||||
headers.append(box)
|
||||
@@ -331,14 +332,10 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
lines=2,
|
||||
ellipsize=Pango.EllipsizeMode.END,
|
||||
tooltip_text=f"{event.time_label} · {event.summary}",
|
||||
css_classes=["timed-event"],
|
||||
css_classes=["timed-event", self._event_color_class(event.color)],
|
||||
)
|
||||
summary = GLib.markup_escape_text(event.summary)
|
||||
color = display_color(event.color)
|
||||
label.set_markup(
|
||||
f'<span foreground="{color}">▌</span> '
|
||||
f"<b>{summary}</b>\n<small>{event.time_label}</small>"
|
||||
)
|
||||
label.set_markup(f"<b>{summary}</b>\n<small>{event.time_label}</small>")
|
||||
column.attach(label, 0, start, 1, end - start)
|
||||
|
||||
overlay = Gtk.Overlay(child=column)
|
||||
@@ -383,6 +380,29 @@ class KhoraWindow(Adw.ApplicationWindow):
|
||||
offset = round(elapsed_minutes / (24 * 60) * GRID_HEIGHT)
|
||||
self._time_indicator.set_margin_top(max(0, offset - 4))
|
||||
|
||||
def _event_color_class(self, value: str | None) -> str:
|
||||
color = display_color(value)
|
||||
class_name = f"event-color-{color.lstrip('#').lower()}"
|
||||
if class_name not in self._event_color_providers:
|
||||
provider = Gtk.CssProvider()
|
||||
foreground = contrasting_foreground(value)
|
||||
provider.load_from_string(
|
||||
f"""
|
||||
.timed-event.{class_name},
|
||||
.all-day-event.{class_name} {{
|
||||
background-color: {color};
|
||||
color: {foreground};
|
||||
}}
|
||||
"""
|
||||
)
|
||||
Gtk.StyleContext.add_provider_for_display(
|
||||
self.get_display(),
|
||||
provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION,
|
||||
)
|
||||
self._event_color_providers[class_name] = provider
|
||||
return class_name
|
||||
|
||||
@staticmethod
|
||||
def _event_row(event: Event) -> Adw.ActionRow:
|
||||
details = f"{event.time_label} · {event.calendar}"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from khora.colors import display_color
|
||||
from khora.colors import contrasting_foreground, display_color
|
||||
|
||||
|
||||
def test_preserves_html_colors() -> None:
|
||||
@@ -16,3 +16,8 @@ def test_converts_xterm_color_cube() -> None:
|
||||
def test_unknown_colors_use_accent_fallback() -> None:
|
||||
assert display_color("auto") == "#3584e4"
|
||||
assert display_color("chartreuse, probably") == "#3584e4"
|
||||
|
||||
|
||||
def test_chooses_contrasting_event_text() -> None:
|
||||
assert contrasting_foreground("dark blue") == "#ffffff"
|
||||
assert contrasting_foreground("yellow") == "#000000"
|
||||
|
||||
Reference in New Issue
Block a user