forked from FoundKeyGang/FoundKey
client: use native Notifications API (#234)
Reviewed-on: FoundKeyGang/FoundKey#234 Changelog: Changed
This commit is contained in:
commit
5b574d40f9
4 changed files with 20 additions and 104 deletions
|
@ -1,67 +0,0 @@
|
|||
<template>
|
||||
<div class="mk-notification-toast" :style="{ zIndex }">
|
||||
<transition :name="$store.state.animation ? 'notification-toast' : ''" appear @after-leave="emit('closed')">
|
||||
<XNotification v-if="showing" :notification="notification" class="notification _panel"/>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import XNotification from './notification.vue';
|
||||
import * as os from '@/os';
|
||||
|
||||
defineProps<{
|
||||
notification: any; // TODO
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'closed'): void;
|
||||
}>();
|
||||
|
||||
const zIndex = os.claimZIndex('high');
|
||||
let showing = $ref(true);
|
||||
|
||||
onMounted(() => {
|
||||
window.setTimeout(() => {
|
||||
showing = false;
|
||||
}, 6000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notification-toast-enter-active, .notification-toast-leave-active {
|
||||
transition: opacity 0.3s, transform 0.3s !important;
|
||||
}
|
||||
.notification-toast-enter-from, .notification-toast-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateX(-250px);
|
||||
}
|
||||
|
||||
.mk-notification-toast {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
width: 250px;
|
||||
top: 32px;
|
||||
padding: 0 32px;
|
||||
pointer-events: none;
|
||||
|
||||
@media (max-width: 700px) {
|
||||
top: initial;
|
||||
bottom: 112px;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
bottom: calc(env(safe-area-inset-bottom, 0px) + 92px);
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
> .notification {
|
||||
height: 100%;
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,7 +9,7 @@ export async function initializeSw() {
|
|||
navigator.serviceWorker.register('/sw.js', { scope: '/', type: 'classic' });
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.active?.postMessage({
|
||||
msg: 'initialize',
|
||||
type: 'initialize',
|
||||
lang,
|
||||
});
|
||||
|
||||
|
@ -33,14 +33,14 @@ export async function initializeSw() {
|
|||
})
|
||||
// When subscribe failed
|
||||
.catch(async (err: Error) => {
|
||||
// 通知が許可されていなかったとき
|
||||
// when notifications were not authorized
|
||||
if (err.name === 'NotAllowedError') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 違うapplicationServerKey (または gcm_sender_id)のサブスクリプションが
|
||||
// 既に存在していることが原因でエラーになった可能性があるので、
|
||||
// そのサブスクリプションを解除しておく
|
||||
// The error may have been caused by the fact that a subscription to a
|
||||
// different applicationServerKey (or gcm_sender_id) already exists, so
|
||||
// unsubscribe to it.
|
||||
const subscription = await registration.pushManager.getSubscription();
|
||||
if (subscription) subscription.unsubscribe();
|
||||
});
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, Ref, ref } from 'vue';
|
||||
import { swInject } from './sw-inject';
|
||||
import { instance } from '@/instance';
|
||||
import { popup as showPopup, popups, pendingApiRequestsCount } from '@/os';
|
||||
import { uploads } from '@/scripts/upload';
|
||||
import * as sound from '@/scripts/sound';
|
||||
|
@ -32,14 +33,12 @@ const dev: Ref<boolean> = ref(_DEV_);
|
|||
const onNotification = (notification: { type: string; id: any; }): void => {
|
||||
if ($i?.mutingNotificationTypes.includes(notification.type)) return;
|
||||
|
||||
if (document.visibilityState === 'visible') {
|
||||
stream.send('readNotification', {
|
||||
id: notification.id,
|
||||
// if push notifications are enabled there is no need to pass the notification along
|
||||
if (!instance.enableServiceWorker) {
|
||||
// service worker is not enabled or set up on the server, pass the notification along
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.active.postMessage({ type: 'notification', body: notification });
|
||||
});
|
||||
|
||||
showPopup(defineAsyncComponent(() => import('@/components/notification-toast.vue')), {
|
||||
notification,
|
||||
}, {}, 'closed');
|
||||
}
|
||||
|
||||
sound.play('notification');
|
||||
|
|
|
@ -24,19 +24,13 @@ self.addEventListener('activate', ev => {
|
|||
});
|
||||
|
||||
self.addEventListener('push', ev => {
|
||||
// クライアント取得
|
||||
ev.waitUntil(self.clients.matchAll({
|
||||
includeUncontrolled: true,
|
||||
type: 'window'
|
||||
}).then(async <K extends keyof pushNotificationDataMap>(clients: readonly WindowClient[]) => {
|
||||
ev.waitUntil((async <K extends keyof pushNotificationDataMap>() => {
|
||||
const data: pushNotificationDataMap[K] = ev.data?.json();
|
||||
|
||||
switch (data.type) {
|
||||
// case 'driveFileCreated':
|
||||
case 'notification':
|
||||
case 'unreadMessagingMessage':
|
||||
// クライアントがあったらストリームに接続しているということなので通知しない
|
||||
if (clients.length != 0) return;
|
||||
return createNotification(data);
|
||||
case 'readAllNotifications':
|
||||
for (const n of await self.registration.getNotifications()) {
|
||||
|
@ -67,7 +61,7 @@ self.addEventListener('push', ev => {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}));
|
||||
})());
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', <K extends keyof pushNotificationDataMap>(ev: ServiceWorkerGlobalScopeEventMap['notificationclick']) => {
|
||||
|
@ -167,24 +161,14 @@ self.addEventListener('notificationclose', <K extends keyof pushNotificationData
|
|||
|
||||
self.addEventListener('message', (ev: ServiceWorkerGlobalScopeEventMap['message']) => {
|
||||
ev.waitUntil((async () => {
|
||||
switch (ev.data) {
|
||||
case 'clear':
|
||||
// Cache Storage全削除
|
||||
await caches.keys()
|
||||
.then(cacheNames => Promise.all(
|
||||
cacheNames.map(name => caches.delete(name))
|
||||
));
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
if (typeof ev.data === 'object') {
|
||||
// E.g. '[object Array]' → 'array'
|
||||
const otype = Object.prototype.toString.call(ev.data).slice(8, -1).toLowerCase();
|
||||
|
||||
if (otype === 'object') {
|
||||
if (ev.data.msg === 'initialize') {
|
||||
switch (ev.data.type) {
|
||||
case 'initialize':
|
||||
swLang.setLang(ev.data.lang);
|
||||
}
|
||||
break;
|
||||
case 'notification':
|
||||
createNotification(ev.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
})());
|
||||
|
|
Loading…
Reference in a new issue