39 files
This commit is contained in:
@@ -158,6 +158,7 @@ class NotificationCoordinator:
|
||||
|
||||
recipients_fired: list[str] = []
|
||||
message = self._render_template(meta, context)
|
||||
nav_url = self._resolve_nav_url(cfg)
|
||||
|
||||
# Multi-parent routing (#687): thin the PARENT recipients down per the
|
||||
# configured policy. Child routes are never touched — a reminder for a
|
||||
@@ -179,7 +180,7 @@ class NotificationCoordinator:
|
||||
notify_service = self._resolve_notify_service(recipient_id)
|
||||
if not notify_service:
|
||||
continue
|
||||
await self._send_to(notify_service, message, meta, context)
|
||||
await self._send_to(notify_service, message, meta, context, nav_url)
|
||||
recipients_fired.append(recipient_id)
|
||||
|
||||
# NOTE: deliberately no unconditional persistent_notification here.
|
||||
@@ -283,6 +284,7 @@ class NotificationCoordinator:
|
||||
}
|
||||
message = "[TEST] " + self._render_template(meta, ctx)
|
||||
cfg = self.storage.get_notification_config(type_id)
|
||||
nav_url = self._resolve_nav_url(cfg)
|
||||
sent: list[str] = []
|
||||
for recipient_id, route in cfg.routes.items():
|
||||
if not route.enabled:
|
||||
@@ -290,7 +292,7 @@ class NotificationCoordinator:
|
||||
notify_service = self._resolve_notify_service(recipient_id)
|
||||
if not notify_service:
|
||||
continue
|
||||
await self._send_to(notify_service, message, meta, ctx)
|
||||
await self._send_to(notify_service, message, meta, ctx, nav_url)
|
||||
sent.append(recipient_id)
|
||||
await self._fire_persistent_notification(type_id, message)
|
||||
return sent
|
||||
@@ -308,6 +310,13 @@ class NotificationCoordinator:
|
||||
child.quiet_hours_start, child.quiet_hours_end, dt_util.now()
|
||||
)
|
||||
|
||||
def _resolve_nav_url(self, cfg) -> str:
|
||||
"""Tap target for this notification: per-type override, else global default."""
|
||||
per_type = (getattr(cfg, "nav_url", "") or "").strip()
|
||||
if per_type:
|
||||
return per_type
|
||||
return str(self.storage.get_setting("notification_nav_url", "/taskmate") or "").strip()
|
||||
|
||||
def _resolve_notify_service(self, recipient_id: str) -> str:
|
||||
if recipient_id.startswith("child:"):
|
||||
child_id = recipient_id.split(":", 1)[1]
|
||||
@@ -349,7 +358,7 @@ class NotificationCoordinator:
|
||||
|
||||
async def _send_to(
|
||||
self, notify_service: str, message: str,
|
||||
meta: "NotificationTypeMeta", context: dict[str, Any],
|
||||
meta: "NotificationTypeMeta", context: dict[str, Any], nav_url: str = "",
|
||||
) -> None:
|
||||
domain, service = (
|
||||
notify_service.split(".", 1) if "." in notify_service
|
||||
@@ -395,6 +404,13 @@ class NotificationCoordinator:
|
||||
push["image"] = photo_url
|
||||
push["attachment"] = {"url": photo_url, "content-type": "jpeg"}
|
||||
|
||||
# Tap target (#734): open a chosen place when the notification body is
|
||||
# tapped. clickAction=Android, url=iOS — the same value works on both.
|
||||
# Only the mobile app honours these; other backends ignore data, so skip.
|
||||
if nav_url and service.startswith("mobile_app"):
|
||||
push["clickAction"] = nav_url
|
||||
push["url"] = nav_url
|
||||
|
||||
if push:
|
||||
data["data"] = push
|
||||
|
||||
@@ -693,6 +709,15 @@ class NotificationCoordinator:
|
||||
await self.storage.async_save()
|
||||
await self.async_setup_schedules()
|
||||
|
||||
async def set_nav_url(self, type_id: str | None, nav_url: str) -> None:
|
||||
"""Set the tap target — global (type_id falsy) or per notification type."""
|
||||
nav_url = (nav_url or "").strip()
|
||||
if type_id:
|
||||
self.storage.set_notification_nav_url(type_id, nav_url)
|
||||
else:
|
||||
self.storage.set_setting("notification_nav_url", nav_url)
|
||||
await self.storage.async_save()
|
||||
|
||||
def _has_outstanding_chores_today(self, child_id: str) -> bool:
|
||||
"""Returns True if the child has at least one chore assigned today
|
||||
that has no approved/pending completion yet."""
|
||||
|
||||
Reference in New Issue
Block a user