summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authortamaina <tamaina@hotmail.co.jp>2023-04-11 14:11:39 +0900
committerGitHub <noreply@github.com>2023-04-11 14:11:39 +0900
commit3a90bcc03cc166632fb64aa76130b63a0ad37a64 (patch)
treee5e6e6e07eb30d1369142d86546b6ab419d31a1b /packages
parentfix #10554 チャンネルの検索用ページとAPIの追加 (#10555) (diff)
downloadmisskey-3a90bcc03cc166632fb64aa76130b63a0ad37a64.tar.gz
misskey-3a90bcc03cc166632fb64aa76130b63a0ad37a64.tar.bz2
misskey-3a90bcc03cc166632fb64aa76130b63a0ad37a64.zip
sw: なんかもうめっちゃ変えた (#10570)
* sw: なんかいろいろ * remove debug code * never renotify * update changelog.md
Diffstat (limited to 'packages')
-rw-r--r--packages/backend/assets/tabler-badges/medal.pngbin0 -> 1241 bytes
-rw-r--r--packages/backend/src/core/NotificationService.ts1
-rw-r--r--packages/backend/src/core/PushNotificationService.ts5
-rw-r--r--packages/frontend/src/ui/_common_/sw-inject.ts21
-rw-r--r--packages/sw/src/scripts/create-notification.ts34
-rw-r--r--packages/sw/src/scripts/operations.ts27
-rw-r--r--packages/sw/src/sw.ts35
-rw-r--r--packages/sw/src/types.ts2
8 files changed, 96 insertions, 29 deletions
diff --git a/packages/backend/assets/tabler-badges/medal.png b/packages/backend/assets/tabler-badges/medal.png
new file mode 100644
index 0000000000..44dc7b8c1e
--- /dev/null
+++ b/packages/backend/assets/tabler-badges/medal.png
Binary files differ
diff --git a/packages/backend/src/core/NotificationService.ts b/packages/backend/src/core/NotificationService.ts
index c7dac061b2..6691c42836 100644
--- a/packages/backend/src/core/NotificationService.ts
+++ b/packages/backend/src/core/NotificationService.ts
@@ -66,6 +66,7 @@ export class NotificationService implements OnApplicationShutdown {
@bindThis
private postReadAllNotifications(userId: User['id']) {
this.globalEventService.publishMainStream(userId, 'readAllNotifications');
+ this.pushNotificationService.pushNotification(userId, 'readAllNotifications', undefined);
}
@bindThis
diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts
index 69020f7e84..fd24831fbc 100644
--- a/packages/backend/src/core/PushNotificationService.ts
+++ b/packages/backend/src/core/PushNotificationService.ts
@@ -15,6 +15,7 @@ type PushNotificationsTypes = {
antenna: { id: string, name: string };
note: Packed<'Note'>;
};
+ 'readAllNotifications': undefined;
};
// Reduce length because push message servers have character limits
@@ -68,6 +69,10 @@ export class PushNotificationService {
});
for (const subscription of subscriptions) {
+ if ([
+ 'readAllNotifications',
+ ].includes(type) && !subscription.sendReadMessage) continue;
+
const pushSubscription = {
endpoint: subscription.endpoint,
keys: {
diff --git a/packages/frontend/src/ui/_common_/sw-inject.ts b/packages/frontend/src/ui/_common_/sw-inject.ts
index a92a06bd3e..c97e2b567b 100644
--- a/packages/frontend/src/ui/_common_/sw-inject.ts
+++ b/packages/frontend/src/ui/_common_/sw-inject.ts
@@ -1,17 +1,18 @@
-import { post } from '@/os';
+import { api, post } from '@/os';
import { $i, login } from '@/account';
import { getAccountFromId } from '@/scripts/get-account-from-id';
import { mainRouter } from '@/router';
+import { deepClone } from '@/scripts/clone';
export function swInject() {
- navigator.serviceWorker.addEventListener('message', ev => {
+ navigator.serviceWorker.addEventListener('message', async ev => {
if (_DEV_) {
console.log('sw msg', ev.data);
}
if (ev.data.type !== 'order') return;
- if (ev.data.loginId !== $i?.id) {
+ if (ev.data.loginId && ev.data.loginId !== $i?.id) {
return getAccountFromId(ev.data.loginId).then(account => {
if (!account) return;
return login(account.token, ev.data.url);
@@ -19,8 +20,18 @@ export function swInject() {
}
switch (ev.data.order) {
- case 'post':
- return post(ev.data.options);
+ case 'post': {
+ const props = deepClone(ev.data.options);
+ // プッシュ通知から来たreply,renoteはtruncateBodyが通されているため、
+ // 完全なノートを取得しなおす
+ if (props.reply) {
+ props.reply = await api('notes/show', { noteId: props.reply.id });
+ }
+ if (props.renote) {
+ props.renote = await api('notes/show', { noteId: props.renote.id });
+ }
+ return post(props);
+ }
case 'push':
if (mainRouter.currentRoute.value.path === ev.data.url) {
return window.scroll({ top: 0, behavior: 'smooth' });
diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts
index 8e214c9850..4d27858253 100644
--- a/packages/sw/src/scripts/create-notification.ts
+++ b/packages/sw/src/scripts/create-notification.ts
@@ -21,7 +21,7 @@ const iconUrl = (name: BadgeNames) => `/static-assets/tabler-badges/${name}.png`
* 1. Find the icon and download png from https://tabler-icons.io/
* 2. vips resize ~/Downloads/icon-name.png vipswork.png 0.4; vips scRGB2BW vipswork.png ~/icon-name.png"[compression=9,strip]"; rm vipswork.png;
* 3. mv ~/icon-name.png ~/misskey/packages/backend/assets/tabler-badges/
- * 4. Add 'icon-name' to badgeNames
+ * 4. Add 'icon-name' to BadgeNames
* 5. Add `badge: iconUrl('icon-name'),`
*/
@@ -168,14 +168,6 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
}];
}
- case 'pollEnded':
- return [t('_notification.pollEnded'), {
- body: data.body.note.text || '',
- badge: iconUrl('chart-arrows'),
- tag: `poll:${data.body.note.id}`,
- data,
- }];
-
case 'receiveFollowRequest':
return [t('_notification.youReceivedFollowRequest'), {
body: getUserName(data.body.user),
@@ -202,6 +194,14 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif
data,
}];
+ case 'achievementEarned':
+ return [t('_notification.achievementEarned'), {
+ body: t(`_achievements._types._${data.body.achievement}.title`),
+ badge: iconUrl('medal'),
+ data,
+ tag: `achievement:${data.body.achievement}`,
+ }];
+
case 'app':
return [data.body.header ?? data.body.body, {
body: data.body.header ? data.body.body : '',
@@ -233,17 +233,29 @@ export async function createEmptyNotification() {
const { t } = i18n;
await globalThis.registration.showNotification(
- t('_notification.emptyPushNotificationMessage'),
+ (new URL(origin)).host,
{
+ body: `Misskey v${_VERSION_}`,
silent: true,
badge: iconUrl('null'),
tag: 'read_notification',
+ actions: [
+ {
+ action: 'markAllAsRead',
+ title: t('markAllAsRead'),
+ },
+ {
+ action: 'settings',
+ title: t('notificationSettings'),
+ },
+ ],
+ data: {},
},
);
setTimeout(async () => {
try {
- await closeNotificationsByTags(['user_visible_auto_notification', 'read_notification']);
+ await closeNotificationsByTags(['user_visible_auto_notification']);
} finally {
res();
}
diff --git a/packages/sw/src/scripts/operations.ts b/packages/sw/src/scripts/operations.ts
index 0978cf9a31..2fd02f9dcb 100644
--- a/packages/sw/src/scripts/operations.ts
+++ b/packages/sw/src/scripts/operations.ts
@@ -4,7 +4,6 @@
*/
import * as Misskey from 'misskey-js';
import { SwMessage, SwMessageOrderType } from '@/types';
-import { acct as getAcct } from '@/filters/user';
import { getAccountFromId } from '@/scripts/get-account-from-id';
import { getUrlWithLoginId } from '@/scripts/login-id';
@@ -17,13 +16,27 @@ export async function api<E extends keyof Misskey.Endpoints>(endpoint: E, userId
return cli.request(endpoint, options, account.token);
}
+// mark-all-as-read送出を1秒間隔に制限する
+const readBlockingStatus = new Map<string, boolean>();
+export function sendMarkAllAsRead(userId: string): Promise<null | undefined | void> {
+ if (readBlockingStatus.get(userId)) return Promise.resolve();
+ readBlockingStatus.set(userId, true);
+ return new Promise(resolve => {
+ setTimeout(() => {
+ readBlockingStatus.set(userId, false);
+ api('notifications/mark-all-as-read', userId)
+ .then(resolve, resolve);
+ }, 1000);
+ });
+}
+
// rendered acctからユーザーを開く
-export function openUser(acct: string, loginId: string) {
+export function openUser(acct: string, loginId?: string) {
return openClient('push', `/@${acct}`, loginId, { acct });
}
// noteIdからノートを開く
-export function openNote(noteId: string, loginId: string) {
+export function openNote(noteId: string, loginId?: string) {
return openClient('push', `/notes/${noteId}`, loginId, { noteId });
}
@@ -33,7 +46,7 @@ export function openAntenna(antennaId: string, loginId: string) {
}
// post-formのオプションから投稿フォームを開く
-export async function openPost(options: any, loginId: string) {
+export async function openPost(options: any, loginId?: string) {
// クエリを作成しておく
let url = '/share?';
if (options.initialText) url += `text=${options.initialText}&`;
@@ -43,7 +56,7 @@ export async function openPost(options: any, loginId: string) {
return openClient('post', url, loginId, { options });
}
-export async function openClient(order: SwMessageOrderType, url: string, loginId: string, query: any = {}) {
+export async function openClient(order: SwMessageOrderType, url: string, loginId?: string, query: any = {}) {
const client = await findClient();
if (client) {
@@ -51,7 +64,7 @@ export async function openClient(order: SwMessageOrderType, url: string, loginId
return client;
}
- return globalThis.clients.openWindow(getUrlWithLoginId(url, loginId));
+ return globalThis.clients.openWindow(loginId ? getUrlWithLoginId(url, loginId) : url);
}
export async function findClient() {
@@ -59,7 +72,7 @@ export async function findClient() {
type: 'window',
});
for (const c of clients) {
- if (!new URL(c.url).searchParams.has('zen')) return c;
+ if (!(new URL(c.url)).searchParams.has('zen')) return c;
}
return null;
}
diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts
index 56050987a0..c1cde8b3c2 100644
--- a/packages/sw/src/sw.ts
+++ b/packages/sw/src/sw.ts
@@ -1,9 +1,9 @@
import { createEmptyNotification, createNotification } from '@/scripts/create-notification';
import { swLang } from '@/scripts/lang';
-import { api } from '@/scripts/operations';
import { PushNotificationDataMap } from '@/types';
import * as swos from '@/scripts/operations';
import { acct as getAcct } from '@/filters/user';
+import { get } from 'idb-keyval';
globalThis.addEventListener('install', ev => {
//ev.waitUntil(globalThis.skipWaiting());
@@ -54,6 +54,10 @@ globalThis.addEventListener('push', ev => {
if ((new Date()).getTime() - data.dateTime > 1000 * 60 * 60 * 24) break;
return createNotification(data);
+ case 'readAllNotifications':
+ await globalThis.registration.getNotifications()
+ .then(notifications => notifications.forEach(n => n.close()));
+ break;
}
await createEmptyNotification();
@@ -68,7 +72,7 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
}
const { action, notification } = ev;
- const data: PushNotificationDataMap[keyof PushNotificationDataMap] = notification.data;
+ const data: PushNotificationDataMap[keyof PushNotificationDataMap] = notification.data ?? {};
const { userId: loginId } = data;
let client: WindowClient | null = null;
@@ -124,13 +128,29 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
break;
case 'unreadAntennaNote':
client = await swos.openAntenna(data.body.antenna.id, loginId);
+ break;
+ default:
+ switch (action) {
+ case 'markAllAsRead':
+ await globalThis.registration.getNotifications()
+ .then(notifications => notifications.forEach(n => n.close()));
+ await get('accounts').then(accounts => {
+ return Promise.all(accounts.map(async account => {
+ await swos.sendMarkAllAsRead(account.id);
+ }));
+ });
+ break;
+ case 'settings':
+ client = await swos.openClient('push', '/settings/notifications', loginId);
+ break;
+ }
}
if (client) {
client.focus();
}
if (data.type === 'notification') {
- api('notifications/mark-all-as-read', data.userId);
+ await swos.sendMarkAllAsRead(loginId);
}
notification.close();
@@ -140,9 +160,12 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv
globalThis.addEventListener('notificationclose', (ev: ServiceWorkerGlobalScopeEventMap['notificationclose']) => {
const data: PushNotificationDataMap[keyof PushNotificationDataMap] = ev.notification.data;
- if (data.type === 'notification') {
- api('notifications/mark-all-as-read', data.userId);
- }
+ ev.waitUntil((async () => {
+ if (data.type === 'notification') {
+ await swos.sendMarkAllAsRead(data.userId);
+ }
+ return;
+ })());
});
globalThis.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => {
diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts
index 7b653e94b7..204ec6198d 100644
--- a/packages/sw/src/types.ts
+++ b/packages/sw/src/types.ts
@@ -17,6 +17,7 @@ type PushNotificationDataSourceMap = {
antenna: { id: string, name: string };
note: Misskey.entities.Note;
};
+ readAllNotifications: undefined;
};
export type PushNotificationData<K extends keyof PushNotificationDataSourceMap> = {
@@ -37,6 +38,7 @@ export type BadgeNames =
| 'at'
| 'chart-arrows'
| 'circle-check'
+ | 'medal'
| 'messages'
| 'plus'
| 'quote'