feat: notification markup support
This commit is contained in:
28
sims/utils/markup.py
Normal file
28
sims/utils/markup.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import re
|
||||||
|
from html import escape as html_escape
|
||||||
|
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version("Pango", "1.0")
|
||||||
|
from gi.repository import GLib, Pango
|
||||||
|
|
||||||
|
# Pango cannot render <img ...> from the freedesktop notification spec; strip it.
|
||||||
|
_IMG_RE = re.compile(r"<img\b[^>]*/?>", re.IGNORECASE)
|
||||||
|
|
||||||
|
|
||||||
|
def render_body_markup(body: str) -> tuple[str, bool]:
|
||||||
|
"""Return ``(text, is_markup)`` for a notification body.
|
||||||
|
|
||||||
|
If the body parses as Pango markup, ``text`` is the cleaned-up markup
|
||||||
|
string and ``is_markup`` is True. Otherwise ``text`` is the XML-escaped
|
||||||
|
plain text and ``is_markup`` is False.
|
||||||
|
"""
|
||||||
|
if not body:
|
||||||
|
return "", False
|
||||||
|
|
||||||
|
candidate = _IMG_RE.sub("", body)
|
||||||
|
try:
|
||||||
|
Pango.parse_markup(candidate, -1, "\0")
|
||||||
|
except GLib.Error:
|
||||||
|
return html_escape(body, quote=False), False
|
||||||
|
return candidate, True
|
||||||
@@ -6,6 +6,8 @@ from fabric.widgets.image import Image
|
|||||||
from fabric.widgets.label import Label
|
from fabric.widgets.label import Label
|
||||||
from gi.repository import GdkPixbuf
|
from gi.repository import GdkPixbuf
|
||||||
|
|
||||||
|
from sims.utils.markup import render_body_markup
|
||||||
|
|
||||||
NOTIFICATION_IMAGE_SIZE = 64
|
NOTIFICATION_IMAGE_SIZE = 64
|
||||||
|
|
||||||
|
|
||||||
@@ -76,9 +78,11 @@ class NotificationWidget(Box):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if body:
|
if body:
|
||||||
|
body_text, body_is_markup = render_body_markup(body)
|
||||||
|
body_kwargs = {"markup": body_text} if body_is_markup else {"label": body_text}
|
||||||
text_children.append(
|
text_children.append(
|
||||||
Label(
|
Label(
|
||||||
label=body,
|
**body_kwargs,
|
||||||
line_wrap="word-char",
|
line_wrap="word-char",
|
||||||
v_align="start",
|
v_align="start",
|
||||||
h_align="start",
|
h_align="start",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from fabric.widgets.image import Image
|
|||||||
from fabric.widgets.label import Label
|
from fabric.widgets.label import Label
|
||||||
|
|
||||||
from sims.services.notification_history import HistoryEntry
|
from sims.services.notification_history import HistoryEntry
|
||||||
|
from sims.utils.markup import render_body_markup
|
||||||
|
|
||||||
|
|
||||||
def _time_ago(ts: float, now: float | None = None) -> str:
|
def _time_ago(ts: float, now: float | None = None) -> str:
|
||||||
@@ -71,9 +72,11 @@ class NotificationHistoryEntryWidget(Box):
|
|||||||
text_children.append(header)
|
text_children.append(header)
|
||||||
|
|
||||||
if entry.body:
|
if entry.body:
|
||||||
|
body_text, body_is_markup = render_body_markup(entry.body)
|
||||||
|
body_kwargs = {"markup": body_text} if body_is_markup else {"label": body_text}
|
||||||
text_children.append(
|
text_children.append(
|
||||||
Label(
|
Label(
|
||||||
label=entry.body,
|
**body_kwargs,
|
||||||
line_wrap="word-char",
|
line_wrap="word-char",
|
||||||
h_align="start",
|
h_align="start",
|
||||||
v_align="start",
|
v_align="start",
|
||||||
|
|||||||
Reference in New Issue
Block a user