initial work on showing notifications through serviceworkers
This commit is contained in:
parent
4c11ac9a27
commit
73fbe89a4b
@ -16,6 +16,7 @@ import backendInteractorService from '../services/backend_interactor_service/bac
|
||||
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||
import { applyTheme, applyConfig } from '../services/style_setter/style_setter.js'
|
||||
import FaviconService from '../services/favicon_service/favicon_service.js'
|
||||
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
|
||||
|
||||
let staticInitialResults = null
|
||||
|
||||
@ -344,6 +345,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
||||
store.dispatch('setLayoutHeight', windowHeight())
|
||||
|
||||
FaviconService.initFaviconService()
|
||||
initServiceWorker()
|
||||
|
||||
window.addEventListener('focus', () => updateFocus())
|
||||
|
||||
const overrides = window.___pleromafe_dev_overrides || {}
|
||||
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
||||
|
@ -2,7 +2,7 @@ import backendInteractorService from '../services/backend_interactor_service/bac
|
||||
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
|
||||
import oauthApi from '../services/new_api/oauth.js'
|
||||
import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'lodash'
|
||||
import { registerPushNotifications, unregisterPushNotifications } from '../services/push/push.js'
|
||||
import { registerPushNotifications, unregisterPushNotifications } from '../services/sw/sw.js'
|
||||
|
||||
// TODO: Unify with mergeOrAdd in statuses.js
|
||||
export const mergeOrAdd = (arr, obj, item) => {
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { showDesktopNotification as swDesktopNotification } from '../sw/sw.js'
|
||||
|
||||
export const showDesktopNotification = (rootState, desktopNotificationOpts) => {
|
||||
if (!('Notification' in window && window.Notification.permission === 'granted')) return
|
||||
if (rootState.statuses.notifications.desktopNotificationSilence) { return }
|
||||
|
||||
const desktopNotification = new window.Notification(desktopNotificationOpts.title, desktopNotificationOpts)
|
||||
// Chrome is known for not closing notifications automatically
|
||||
// according to MDN, anyway.
|
||||
setTimeout(desktopNotification.close.bind(desktopNotification), 5000)
|
||||
swDesktopNotification(desktopNotificationOpts)
|
||||
}
|
||||
|
@ -10,8 +10,12 @@ function urlBase64ToUint8Array (base64String) {
|
||||
return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0)))
|
||||
}
|
||||
|
||||
function isSWSupported () {
|
||||
return 'serviceWorker' in navigator
|
||||
}
|
||||
|
||||
function isPushSupported () {
|
||||
return 'serviceWorker' in navigator && 'PushManager' in window
|
||||
return 'PushManager' in window
|
||||
}
|
||||
|
||||
function getOrCreateServiceWorker () {
|
||||
@ -39,7 +43,7 @@ function unsubscribePush (registration) {
|
||||
}
|
||||
|
||||
function deleteSubscriptionFromBackEnd (token) {
|
||||
return window.fetch('/api/v1/push/subscription/', {
|
||||
return fetch('/api/v1/push/subscription/', {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
@ -78,6 +82,20 @@ function sendSubscriptionToBackEnd (subscription, token, notificationVisibility)
|
||||
return responseData
|
||||
})
|
||||
}
|
||||
export function initServiceWorker () {
|
||||
if (!isSWSupported()) return
|
||||
getOrCreateServiceWorker()
|
||||
}
|
||||
|
||||
export async function showDesktopNotification (content) {
|
||||
const { active: sw } = await window.navigator.serviceWorker.getRegistration()
|
||||
sw.postMessage({ type: 'desktopNotification', content })
|
||||
}
|
||||
|
||||
export async function updateFocus () {
|
||||
const { active: sw } = await window.navigator.serviceWorker.getRegistration()
|
||||
sw.postMessage({ type: 'updateFocus' })
|
||||
}
|
||||
|
||||
export function registerPushNotifications (isEnabled, vapidPublicKey, token, notificationVisibility) {
|
||||
if (isPushSupported()) {
|
||||
@ -98,13 +116,8 @@ export function unregisterPushNotifications (token) {
|
||||
})
|
||||
.then(([registration, unsubResult]) => {
|
||||
if (!unsubResult) {
|
||||
console.warn('Push subscription cancellation wasn\'t successful, killing SW anyway...')
|
||||
console.warn('Push subscription cancellation wasn\'t successful')
|
||||
}
|
||||
return registration.unregister().then((result) => {
|
||||
if (!result) {
|
||||
console.warn('Failed to kill SW')
|
||||
}
|
||||
})
|
||||
})
|
||||
]).catch((e) => console.warn(`Failed to disable Web Push Notifications: ${e.message}`))
|
||||
}
|
37
src/sw.js
37
src/sw.js
@ -13,9 +13,9 @@ const i18n = createI18n({
|
||||
messages
|
||||
})
|
||||
|
||||
function isEnabled () {
|
||||
return localForage.getItem('vuex-lz')
|
||||
.then(data => data.config.webPushNotifications)
|
||||
const state = {
|
||||
lastFocused: null,
|
||||
notificationIds: new Set()
|
||||
}
|
||||
|
||||
function getWindowClients () {
|
||||
@ -29,11 +29,11 @@ const setLocale = async () => {
|
||||
i18n.locale = locale
|
||||
}
|
||||
|
||||
const maybeShowNotification = async (event) => {
|
||||
const enabled = await isEnabled()
|
||||
const showPushNotification = async (event) => {
|
||||
const activeClients = await getWindowClients()
|
||||
await setLocale()
|
||||
if (enabled && (activeClients.length === 0)) {
|
||||
// Only show push notifications if all tabs/windows are closed
|
||||
if (activeClients.length === 0) {
|
||||
const data = event.data.json()
|
||||
|
||||
const url = `${self.registration.scope}api/v1/notifications/${data.notification_id}`
|
||||
@ -48,8 +48,27 @@ const maybeShowNotification = async (event) => {
|
||||
}
|
||||
|
||||
self.addEventListener('push', async (event) => {
|
||||
console.log(event)
|
||||
if (event.data) {
|
||||
event.waitUntil(maybeShowNotification(event))
|
||||
event.waitUntil(showPushNotification(event))
|
||||
}
|
||||
})
|
||||
|
||||
self.addEventListener('message', async (event) => {
|
||||
const { type, content } = event.data
|
||||
console.log(event)
|
||||
|
||||
if (type === 'desktopNotification') {
|
||||
const { title, body, icon, id } = content
|
||||
if (state.notificationIds.has(id)) return
|
||||
state.notificationIds.add(id)
|
||||
setTimeout(() => state.notificationIds.remove(id), 10000)
|
||||
self.registration.showNotification('SWTEST: ' + title, { body, icon })
|
||||
}
|
||||
|
||||
if (type === 'updateFocus') {
|
||||
state.lastFocused = event.source.id
|
||||
console.log(state)
|
||||
}
|
||||
})
|
||||
|
||||
@ -59,7 +78,9 @@ self.addEventListener('notificationclick', (event) => {
|
||||
event.waitUntil(getWindowClients().then((list) => {
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const client = list[i]
|
||||
if (client.url === '/' && 'focus' in client) { return client.focus() }
|
||||
if (state.lastFocused === null || client.id === state.lastFocused) {
|
||||
if ('focus' in client) return client.focus()
|
||||
}
|
||||
}
|
||||
|
||||
if (clients.openWindow) return clients.openWindow('/')
|
||||
|
Loading…
Reference in New Issue
Block a user