Cosmetic changess
parent
b197ea3ab6
commit
6e95d62726
|
@ -474,7 +474,7 @@ type apiWebPushUpdateSubscriptionRequest struct {
|
||||||
Topics []string `json:"topics"`
|
Topics []string `json:"topics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of possible Web Push events
|
// List of possible Web Push events (see sw.js)
|
||||||
const (
|
const (
|
||||||
webPushMessageEvent = "message"
|
webPushMessageEvent = "message"
|
||||||
webPushExpiringEvent = "subscription_expiring"
|
webPushExpiringEvent = "subscription_expiring"
|
||||||
|
@ -486,8 +486,8 @@ type webPushPayload struct {
|
||||||
Message *message `json:"message"`
|
Message *message `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWebPushPayload(subscriptionID string, message *message) webPushPayload {
|
func newWebPushPayload(subscriptionID string, message *message) *webPushPayload {
|
||||||
return webPushPayload{
|
return &webPushPayload{
|
||||||
Event: webPushMessageEvent,
|
Event: webPushMessageEvent,
|
||||||
SubscriptionID: subscriptionID,
|
SubscriptionID: subscriptionID,
|
||||||
Message: message,
|
Message: message,
|
||||||
|
@ -498,8 +498,8 @@ type webPushControlMessagePayload struct {
|
||||||
Event string `json:"event"`
|
Event string `json:"event"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWebPushSubscriptionExpiringPayload() webPushControlMessagePayload {
|
func newWebPushSubscriptionExpiringPayload() *webPushControlMessagePayload {
|
||||||
return webPushControlMessagePayload{
|
return &webPushControlMessagePayload{
|
||||||
Event: webPushExpiringEvent,
|
Event: webPushExpiringEvent,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { NetworkFirst } from "workbox-strategies";
|
||||||
|
|
||||||
import { dbAsync } from "../src/app/db";
|
import { dbAsync } from "../src/app/db";
|
||||||
|
|
||||||
import { getNotificationParams, icon, badge } from "../src/app/notificationUtils";
|
import { toNotificationParams, icon, badge } from "../src/app/notificationUtils";
|
||||||
|
|
||||||
import i18n from "../src/app/i18n";
|
import i18n from "../src/app/i18n";
|
||||||
|
|
||||||
|
@ -40,50 +40,70 @@ const addNotification = async ({ subscriptionId, message }) => {
|
||||||
self.navigator.setAppBadge?.(badgeCount);
|
self.navigator.setAppBadge?.(badgeCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a received web push message and show notification.
|
||||||
|
*
|
||||||
|
* Since the service worker cannot play a sound, we send a broadcast to the web app, which (if it is running)
|
||||||
|
* receives the broadcast and plays a sound (see web/src/app/WebPush.js).
|
||||||
|
*/
|
||||||
|
const handlePushMessage = async (data) => {
|
||||||
|
const { subscription_id: subscriptionId, message } = data;
|
||||||
|
|
||||||
|
broadcastChannel.postMessage(message); // To potentially play sound
|
||||||
|
|
||||||
|
await addNotification({ subscriptionId, message });
|
||||||
|
await self.registration.showNotification(
|
||||||
|
...toNotificationParams({
|
||||||
|
subscriptionId,
|
||||||
|
message,
|
||||||
|
defaultTitle: message.topic,
|
||||||
|
topicRoute: new URL(message.topic, self.location.origin).toString(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a received web push subscription expiring.
|
||||||
|
*/
|
||||||
|
const handlePushSubscriptionExpiring = async (data) => {
|
||||||
|
await self.registration.showNotification(i18n.t("web_push_subscription_expiring_title"), {
|
||||||
|
body: i18n.t("web_push_subscription_expiring_body"),
|
||||||
|
icon,
|
||||||
|
data,
|
||||||
|
badge,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle unknown push message. We can't ignore the push, since
|
||||||
|
* permission can be revoked by the browser.
|
||||||
|
*/
|
||||||
|
const handlePushUnknown = async (data) => {
|
||||||
|
await self.registration.showNotification(i18n.t("web_push_unknown_notification_title"), {
|
||||||
|
body: i18n.t("web_push_unknown_notification_body"),
|
||||||
|
icon,
|
||||||
|
data,
|
||||||
|
badge,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a received web push notification
|
* Handle a received web push notification
|
||||||
* @param {object} data see server/types.go, type webPushPayload
|
* @param {object} data see server/types.go, type webPushPayload
|
||||||
*/
|
*/
|
||||||
const handlePush = async (data) => {
|
const handlePush = async (data) => {
|
||||||
if (data.event === "subscription_expiring") {
|
if (data.event === "message") {
|
||||||
await self.registration.showNotification(i18n.t("web_push_subscription_expiring_title"), {
|
await handlePushMessage(data);
|
||||||
body: i18n.t("web_push_subscription_expiring_body"),
|
} else if (data.event === "subscription_expiring") {
|
||||||
icon,
|
await handlePushSubscriptionExpiring(data);
|
||||||
data,
|
|
||||||
badge,
|
|
||||||
});
|
|
||||||
} else if (data.event === "message") {
|
|
||||||
const { subscription_id: subscriptionId, message } = data;
|
|
||||||
|
|
||||||
// see: web/src/app/WebPush.js
|
|
||||||
// the service worker cannot play a sound, so if the web app
|
|
||||||
// is running, it receives the broadcast and plays it.
|
|
||||||
broadcastChannel.postMessage(message);
|
|
||||||
|
|
||||||
await addNotification({ subscriptionId, message });
|
|
||||||
|
|
||||||
await self.registration.showNotification(
|
|
||||||
...getNotificationParams({
|
|
||||||
subscriptionId,
|
|
||||||
message,
|
|
||||||
defaultTitle: message.topic,
|
|
||||||
topicRoute: new URL(message.topic, self.location.origin).toString(),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// We can't ignore the push, since permission can be revoked by the browser
|
await handlePushUnknown(data);
|
||||||
await self.registration.showNotification(i18n.t("web_push_unknown_notification_title"), {
|
|
||||||
body: i18n.t("web_push_unknown_notification_body"),
|
|
||||||
icon,
|
|
||||||
data,
|
|
||||||
badge,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a user clicking on the displayed notification from `showNotification`
|
* Handle a user clicking on the displayed notification from `showNotification`.
|
||||||
* This is also called when the user clicks on an action button
|
* This is also called when the user clicks on an action button.
|
||||||
*/
|
*/
|
||||||
const handleClick = async (event) => {
|
const handleClick = async (event) => {
|
||||||
const clients = await self.clients.matchAll({ type: "window" });
|
const clients = await self.clients.matchAll({ type: "window" });
|
||||||
|
@ -195,7 +215,7 @@ self.addEventListener("notificationclick", (event) => {
|
||||||
event.waitUntil(handleClick(event));
|
event.waitUntil(handleClick(event));
|
||||||
});
|
});
|
||||||
|
|
||||||
// see https://vite-pwa-org.netlify.app/guide/inject-manifest.html#service-worker-code
|
// See https://vite-pwa-org.netlify.app/guide/inject-manifest.html#service-worker-code
|
||||||
// self.__WB_MANIFEST is the workbox injection point that injects the manifest of the
|
// self.__WB_MANIFEST is the workbox injection point that injects the manifest of the
|
||||||
// vite dist files and their revision ids, for example:
|
// vite dist files and their revision ids, for example:
|
||||||
// [{"revision":"aaabbbcccdddeeefff12345","url":"/index.html"},...]
|
// [{"revision":"aaabbbcccdddeeefff12345","url":"/index.html"},...]
|
||||||
|
@ -204,7 +224,7 @@ precacheAndRoute(
|
||||||
self.__WB_MANIFEST
|
self.__WB_MANIFEST
|
||||||
);
|
);
|
||||||
|
|
||||||
// delete any cached old dist files from previous service worker versions
|
// Delete any cached old dist files from previous service worker versions
|
||||||
cleanupOutdatedCaches();
|
cleanupOutdatedCaches();
|
||||||
|
|
||||||
if (import.meta.env.MODE !== "development") {
|
if (import.meta.env.MODE !== "development") {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { playSound, topicDisplayName, topicShortUrl, urlB64ToUint8Array } from "./utils";
|
import { playSound, topicDisplayName, topicShortUrl, urlB64ToUint8Array } from "./utils";
|
||||||
import { getNotificationParams } from "./notificationUtils";
|
import { toNotificationParams } from "./notificationUtils";
|
||||||
import prefs from "./Prefs";
|
import prefs from "./Prefs";
|
||||||
import routes from "../components/routes";
|
import routes from "../components/routes";
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class Notifier {
|
||||||
|
|
||||||
const registration = await this.serviceWorkerRegistration();
|
const registration = await this.serviceWorkerRegistration();
|
||||||
await registration.showNotification(
|
await registration.showNotification(
|
||||||
...getNotificationParams({
|
...toNotificationParams({
|
||||||
subscriptionId: subscription.id,
|
subscriptionId: subscription.id,
|
||||||
message: notification,
|
message: notification,
|
||||||
defaultTitle,
|
defaultTitle,
|
||||||
|
|
|
@ -39,7 +39,7 @@ const isImage = (filenameOrUrl) => filenameOrUrl?.match(/\.(png|jpe?g|gif|webp)$
|
||||||
export const icon = "/static/images/ntfy.png";
|
export const icon = "/static/images/ntfy.png";
|
||||||
export const badge = "/static/images/mask-icon.svg";
|
export const badge = "/static/images/mask-icon.svg";
|
||||||
|
|
||||||
export const getNotificationParams = ({ subscriptionId, message, defaultTitle, topicRoute }) => {
|
export const toNotificationParams = ({ subscriptionId, message, defaultTitle, topicRoute }) => {
|
||||||
const image = isImage(message.attachment?.name) ? message.attachment.url : undefined;
|
const image = isImage(message.attachment?.name) ? message.attachment.url : undefined;
|
||||||
|
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
|
// https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API
|
||||||
|
|
Loading…
Reference in New Issue