- Web Push: push_sw.js service worker + VAPID subscription registered on login; Matrix pusher registered pointing to Sygnal on https://matrix.m8chat.au/_matrix/push/v1/notify - Chat: tap image -> fullscreen InteractiveViewer (pinch/zoom) - Rooms: public room browser via Matrix room directory (FAB + empty state) Build fixes applied to web_push_service.dart: - dart:js_interop_unsafe import added for getProperty on JSObject - client.setPusher -> client.postPusher (matrix 0.33.0 API) - keyBytes.toJS removed (JSUint8Array already a JS type) - register() script URL coerced with .toJS (String -> JSAny) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
1.9 KiB
JavaScript
65 lines
1.9 KiB
JavaScript
// Version: 1.0.0 | Created: 2026-04-27
|
|
// Web Push service worker for M8Chat.
|
|
// Receives push events from the browser and shows system notifications.
|
|
// This script is registered separately from flutter_service_worker.js.
|
|
|
|
'use strict';
|
|
|
|
self.addEventListener('push', function (event) {
|
|
if (!event.data) return;
|
|
|
|
let data = {};
|
|
try {
|
|
data = event.data.json();
|
|
} catch (_) {
|
|
data = { notification: { body: event.data.text() } };
|
|
}
|
|
|
|
// Sygnal delivers: { notification: { content: { body, msgtype, ... }, room_name, sender_display_name, ... } }
|
|
const notif = data.notification || {};
|
|
const content = notif.content || {};
|
|
|
|
const sender = notif.sender_display_name || notif.sender || 'M8Chat';
|
|
const room = notif.room_name || notif.room_alias || '';
|
|
const body = content.body || notif.body || 'New message';
|
|
|
|
const title = room ? `${sender} in ${room}` : sender;
|
|
|
|
const options = {
|
|
body: body,
|
|
icon: '/icons/Icon-192.png',
|
|
badge: '/icons/Icon-192.png',
|
|
tag: notif.room_id || 'm8chat',
|
|
data: {
|
|
roomId: notif.room_id,
|
|
url: self.location.origin + (notif.room_id
|
|
? '/rooms/' + encodeURIComponent(notif.room_id)
|
|
: '/rooms'),
|
|
},
|
|
requireInteraction: false,
|
|
};
|
|
|
|
event.waitUntil(self.registration.showNotification(title, options));
|
|
});
|
|
|
|
self.addEventListener('notificationclick', function (event) {
|
|
event.notification.close();
|
|
|
|
const url = (event.notification.data && event.notification.data.url)
|
|
? event.notification.data.url
|
|
: self.location.origin + '/rooms';
|
|
|
|
event.waitUntil(
|
|
clients.matchAll({ type: 'window', includeUncontrolled: true }).then(function (clientList) {
|
|
for (const client of clientList) {
|
|
if (client.url === url && 'focus' in client) {
|
|
return client.focus();
|
|
}
|
|
}
|
|
if (clients.openWindow) {
|
|
return clients.openWindow(url);
|
|
}
|
|
})
|
|
);
|
|
});
|