diff --git a/timetagger/app/dialogs.py b/timetagger/app/dialogs.py
index d2162234..4833f5a7 100644
--- a/timetagger/app/dialogs.py
+++ b/timetagger/app/dialogs.py
@@ -1508,6 +1508,15 @@ def __init__(self, canvas):
self._record = None
self._no_user_edit_yet = True
+ # Enable stopping a record via the notification
+ if window.navigator.serviceWorker:
+ try:
+ window.navigator.serviceWorker.addEventListener(
+ "message", self.on_notificationclick
+ )
+ except Exception:
+ pass
+
def open(self, mode, record, callback=None):
"""Show/open the dialog for the given record. On submit, the
record will be pushed to the store and callback (if given) will
@@ -1827,6 +1836,9 @@ def submit(self):
# Apply
window.store.records.put(self._record)
super().submit(self._record)
+ # Notify
+ if self._lmode == "start":
+ self.send_notification(self._record)
# Start pomo?
if window.simplesettings.get("pomodoro_enabled"):
if self._lmode == "start":
@@ -1855,10 +1867,43 @@ def resume_record(self):
if not (t1 < now < t2):
t1, t2 = self._canvas.range.get_today_range()
self._canvas.range.animate_range(t1, t2)
+ # Notify
+ self.send_notification(record)
# Start pomo?
if window.simplesettings.get("pomodoro_enabled"):
self._canvas.pomodoro_dialog.start_work()
+ def send_notification(self, record):
+ if not window.simplesettings.get("notifications"):
+ return
+ if window.Notification and Notification.permission != "granted":
+ return
+
+ title = "TimeTagger is tracking time"
+ actions = [
+ {"action": "stop", "title": "Stop"},
+ ]
+ options = {
+ "icon": "timetagger192_sf.png",
+ "body": record.ds or "",
+ "requireInteraction": True,
+ "tag": "timetagger-running", # replace previous notifications
+ }
+ # If we show the notification via the service worker, we
+ # can show actions, making the flow easier for users.
+ if window.pwa and window.pwa.sw_reg:
+ options.actions = actions
+ window.pwa.sw_reg.showNotification(title, options)
+ else:
+ Notification(title, options)
+
+ def on_notificationclick(self, message_event):
+ event = message_event.data
+ if event.type != "notificationclick":
+ return
+ if event.action == "stop":
+ self._stop_all_running_records()
+
class TargetHelper:
"""A little class to help with targets. Because targets occur in two dialogs."""
@@ -3863,6 +3908,10 @@ def open(self, callback=None):
+