Add a button for enabling push notifications (#158)

Safari requires some user interaction to subscribe to push notifications ([see this](https://developer.apple.com/documentation/usernotifications/sending_web_push_notifications_in_web_apps_safari_and_other_browsers)), so this PR adds a button to the navigation menu that requests notification permissions and does the subscription stuff. It also hides the "Mobile App" button from PWA

Side effect of this PR is that push permissions aren't gonna be requested automatically on other platforms anymore like they used to. Also it's probably a good idea to add this button somewhere else too because it's not very accessible on desktop
![image](/attachments/f2f78028-9e5f-484f-aa98-59eb60e3ccd5)

Co-authored-by: borntolurk <borntolurk@rdrama.net>
Reviewed-on: #158
Co-authored-by: borntolurk <borntolurk@noreply.fsdfsd.net>
Co-committed-by: borntolurk <borntolurk@noreply.fsdfsd.net>
pull/161/head
Aevann 2023-06-29 21:09:27 +03:00
parent 1b48488996
commit ab554c163c
5 changed files with 69 additions and 32 deletions

View File

@ -234,3 +234,10 @@ for (const input of inputs) {
if (parseInt(input.value) > parseInt(input.max)) input.value = input.max;
};
}
if (!('serviceWorker' in navigator && 'PushManager' in window)) {
let e = document.getElementById("enable-push-nav-item").style = "display: none";
if (e) {
e.style = "display: none"
}
}

View File

@ -605,3 +605,51 @@ document.querySelectorAll('form').forEach(form => {
form.classList.add('is-submitting');
});
});
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function updateSubscriptionOnServer(subscription, apiEndpoint) {
const formData = new FormData();
formData.append("subscription_json", JSON.stringify(subscription));
const xhr = createXhrWithFormKey(
apiEndpoint,
'POST',
formData
);
xhr[0].send(xhr[1]);
}
function enablePushNotifications() {
if (!('serviceWorker' in navigator && 'PushManager' in window)) return;
let publicKeyElement = document.getElementById('VAPID_PUBLIC_KEY');
if (!publicKeyElement) return;
let publicKey = urlB64ToUint8Array(publicKeyElement.value);
navigator.serviceWorker.getRegistration("/assets/js/service_worker.js").then((reg) => {
return reg.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: publicKey,
})
}).then((subscription) => {
updateSubscriptionOnServer(subscription, "/push_subscribe")
alert("Push notifications are enabled!")
}).catch((e) => {
alert("Please give the site access to notifications!")
console.log(e)
})
}

View File

@ -1,33 +1,5 @@
'use strict';
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
function updateSubscriptionOnServer(subscription, apiEndpoint) {
const formData = new FormData();
formData.append("subscription_json", JSON.stringify(subscription));
const xhr = createXhrWithFormKey(
apiEndpoint,
'POST',
formData
);
xhr[0].send(xhr[1]);
}
function subscribeUser(swRegistration, applicationServerPublicKey, apiEndpoint) {
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({

View File

@ -146,7 +146,7 @@
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto d-none d-md-flex">
<ul class="navbar-nav ml-auto d-none d-md-flex mr-3">
{% if not (v and v.patron) %}
<a class="btn btn-primary mr-3 pb-0 pt-2 donate-link" id="header--donate--item" href="/donate">Donate</a>
@ -238,7 +238,13 @@
<a class="dropdown-item" href="{{v.url}}"><i class="fas fa-user-circle fa-fw mr-3"></i>My profile</a>
<a class="dropdown-item" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
<a class="dropdown-item" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
<input hidden id="VAPID_PUBLIC_KEY" value="{{VAPID_PUBLIC_KEY}}">
<button id="enable-push-nav-item" type="button" class="dropdown-item" data-nonce="{{g.nonce}}" data-onclick="enablePushNotifications()"><i class="fas fa-bell fa-fw mr-3"></i>Enable push notifications</button>
{% if g.browser != 'webview' %}
<a class="dropdown-item" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
{% endif %}
<a class="dropdown-item donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>
@ -294,7 +300,12 @@
<a class="nav-link" href="/settings/personal"><i class="fas fa-cog fa-fw mr-3"></i>Settings</a>
</li>
<a class="nav-item nav-link" href="/app"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
{% if g.browser == 'webview' %}
<a class="nav-item nav-link" href="/app" id="mobile-app-nav-item"><i class="fas fa-mobile fa-fw mr-3"></i>Mobile app</a>
{% endif %}
<button type="button" class="nav-item nav-link" data-nonce="{{g.nonce}}" data-onclick="enablePushNotifications()"><i class="fas fa-bell fa-fw mr-3"></i>Enable push notifications</button>
<a class="nav-item nav-link donate-link" rel="nofollow noopener" href="/donate"><i class="fas fa-dollar-sign fa-fw mr-3"></i>Donate</a>

View File

@ -162,7 +162,6 @@
{% if request.path == '/' and v %}
<script defer src="{{'js/register_service_worker.js' | asset}}"></script>
<input hidden id="VAPID_PUBLIC_KEY" value="{{VAPID_PUBLIC_KEY}}">
{% endif %}
{% if False and request.path == '/' and g.browser != 'webview' and time.time() > session.get('tooltip_dismissed',0)+86400*30 %}