diff --git a/src/client/scripts/initialize-sw.ts b/src/client/scripts/initialize-sw.ts index abbfe4f4e2..7a364f10c3 100644 --- a/src/client/scripts/initialize-sw.ts +++ b/src/client/scripts/initialize-sw.ts @@ -2,6 +2,7 @@ import { instance } from '@/instance'; import { $i } from '@/account'; import { api } from '@/os'; import { lang } from '@/config'; +import { SwMessage } from '@/sw/types'; export async function initializeSw() { if (instance.swPublickey && @@ -15,9 +16,10 @@ export async function initializeSw() { msg: 'initialize', lang, }); + // SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters registration.pushManager.subscribe({ - userVisibleOnly: false, + userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(instance.swPublickey) }).then(subscription => { function encode(buffer: ArrayBuffer | null) { @@ -48,6 +50,13 @@ export async function initializeSw() { } } +navigator.serviceWorker.addEventListener('message', ev => { + const data = ev.data as SwMessage; + if (data.type !== 'order') return; + + data.order +}); + /** * Convert the URL safe base64 string to a Uint8Array * @param base64String base64 string diff --git a/src/client/sw/notification-read.ts b/src/client/sw/notification-read.ts index e45f2623cf..bf0245fbf9 100644 --- a/src/client/sw/notification-read.ts +++ b/src/client/sw/notification-read.ts @@ -1,3 +1,5 @@ +declare var self: ServiceWorkerGlobalScope; + import { get } from 'idb-keyval'; import { pushNotificationData } from '../../types'; @@ -48,6 +50,8 @@ class SwNotificationRead { i: account.token, notificationIds: account.queue }) + }).then(res => { + self.registration.showNotification('notificationread', { body: `${account.queue}, ${res.ok}` }); }); }, 100); } diff --git a/src/client/sw/open-client.ts b/src/client/sw/open-client.ts new file mode 100644 index 0000000000..89f921e7d4 --- /dev/null +++ b/src/client/sw/open-client.ts @@ -0,0 +1,41 @@ +/* + * Openers + * クライアントを開く関数。 + * ユーザー、ノート、投稿フォーム、トークルーム + */ +declare var self: ServiceWorkerGlobalScope; + +import { SwMessage, swMessageOrderType } from './types'; + +// acctからユーザーを開く +export async function openUser(acct: string, loginId: string) { + open('push-user', { acct }, `${origin}/${acct}?loginId=${loginId}`, loginId) +} + +// post-formのオプションから投稿フォームを開く +export async function openPost(options: any, loginId: string) { + // Build share queries from options + let url = `${origin}/?`; + if (options.initialText) url += `text=${options.initialText}&`; + if (options.reply) url += `replyId=${options.reply.id}&`; + if (options.renote) url += `renoteId=${options.renote.id}&`; + url += `loginId=${loginId}`; + + open('post', { options }, url, loginId) +} + +async function open(order: swMessageOrderType, query: any, url: string, loginId: string) { + const client = await self.clients.matchAll({ + includeUncontrolled: true, + type: 'window' + }).then(clients => clients.length > 0 ? clients[0] : null); + + if (client) { + client.postMessage({ type: 'order', ...query, order, loginId, url } as SwMessage); + + if ('focus' in client) (client as any).focus(); + return; + } + + return self.clients.openWindow(url); +} diff --git a/src/client/sw/sw.ts b/src/client/sw/sw.ts index b92d337fd6..7e309c699b 100644 --- a/src/client/sw/sw.ts +++ b/src/client/sw/sw.ts @@ -10,7 +10,7 @@ import { pushNotificationData } from '../../types'; //#region Lifecycle: Install self.addEventListener('install', ev => { - self.skipWaiting(); + ev.waitUntil(self.skipWaiting()); }); //#endregion @@ -38,7 +38,8 @@ self.addEventListener('fetch', ev => { self.addEventListener('push', ev => { // クライアント取得 ev.waitUntil(self.clients.matchAll({ - includeUncontrolled: true + includeUncontrolled: true, + type: 'window' }).then(async clients => { // // クライアントがあったらストリームに接続しているということなので通知しない // if (clients.length != 0) return; @@ -70,11 +71,21 @@ self.addEventListener('push', ev => { //#endregion //#region Notification -self.addEventListener('notificationclick', ev => { +self.addEventListener('notificationclick', async ev => { const { action, notification } = ev; console.log('click', action, notification) const data: pushNotificationData = notification.data; const { origin } = location; + const client = self.clients.matchAll({ + includeUncontrolled: true, + type: 'window' + }).then(clients => { + for (const client of clients) { + client.postMessage(notification.data); + if ('focus' in client) (client as any).focus() + console.log('postMessage', client) + } + }); const suffix = `?loginId=${data.userId}`; @@ -82,12 +93,12 @@ self.addEventListener('notificationclick', ev => { case 'showUser': switch (data.body.type) { case 'reaction': - self.clients.openWindow(`${origin}/users/${data.body.user.id}${suffix}`); + await self.clients.openWindow(`${origin}/users/${data.body.user.id}${suffix}`); break; default: if ('note' in data.body) { - self.clients.openWindow(`${origin}/users/${data.body.note.user.id}${suffix}`); + await self.clients.openWindow(`${origin}/users/${data.body.note.user.id}${suffix}`); } } break; diff --git a/src/client/sw/types.ts b/src/client/sw/types.ts new file mode 100644 index 0000000000..6e8b7abfab --- /dev/null +++ b/src/client/sw/types.ts @@ -0,0 +1,9 @@ +export type swMessageOrderType = 'post' | 'push-user' | 'push-note' | 'push-messaging-room' + +export type SwMessage = { + type: 'order'; + order: swMessageOrderType; + loginId: string; + url: string; + [x: string]: any; +};