Skip to content

Commit 5bc2768

Browse files
Improve browser notification permission request
- Only request permission when the timer is started. Don't be annoying if the user isn't even going to use the feature - Add a justification for why the permission is requested and how to disable the notifications - Handle case of no browser notification support - Move all desktop notification related code into its own file Signed-off-by: Marcel Robitaille <[email protected]>
1 parent 2a63121 commit 5bc2768

File tree

3 files changed

+57
-13
lines changed

3 files changed

+57
-13
lines changed

src/components/RecipeTimer.vue

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { linkTo } from "@nextcloud/router"
1616
1717
import { showSimpleAlertModal } from "cookbook/js/modals"
1818
19+
import * as browserNotifications from "cookbook/js/browser_notifications"
20+
1921
export default {
2022
name: "RecipeTimer",
2123
props: {
@@ -63,9 +65,6 @@ export default {
6365
this.resetTimeDisplay()
6466
},
6567
},
66-
async created() {
67-
this.notificationPermission = await Notification.requestPermission()
68-
},
6968
mounted() {
7069
this.resetTimeDisplay()
7170
// Start loading the sound early so it's ready to go when we need to
@@ -82,6 +81,14 @@ export default {
8281
this.audio.loop = true
8382
},
8483
methods: {
84+
onTimerStart() {
85+
browserNotifications.requestPermission({
86+
justification: [
87+
t("cookbook", "Please enable browser notifications to receive an alert when the timer is over."),
88+
t("cookbook", "You can disable these notifications at any time in the \"Cookbook settings\" dialog."),
89+
],
90+
})
91+
},
8592
onTimerEnd() {
8693
window.clearInterval(this.countdown)
8794
const $this = this
@@ -96,15 +103,7 @@ export default {
96103
this.audio.play()
97104
98105
const message = t("cookbook", "Cooking time is up!")
99-
100-
if (this.notificationPermission === "granted") {
101-
const notification = new Notification(message)
102-
notification.addEventListener("error", (error) => {
103-
// eslint-disable-next-line no-console
104-
console.error("Error showing notification:", error)
105-
})
106-
}
107-
106+
await browserNotifications.notify(message)
108107
await showSimpleAlertModal(message)
109108
110109
// Stop audio after the alert is confirmed
@@ -137,6 +136,7 @@ export default {
137136
if (this.countdown === null) {
138137
// Pass this to callback function
139138
const $this = this
139+
$this.onTimerStart()
140140
this.countdown = window.setInterval(() => {
141141
$this.seconds -= 1
142142
if ($this.seconds < 0) {

src/components/SimpleAlertModal.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<template>
22
<NcModal :title="title" @close="$close">
33
<div class="modal__wrapper">
4-
<div class="modal__content">{{ content }}</div>
4+
<div v-if="!multiline" class="modal__content">{{ content }}</div>
5+
<p v-else v-for="line in content" class="modal__content">{{ line }}</p>
56
<div class="modal__button-bar">
67
<NcButton type="primary" @click="$close">{{
78
t("cookbook", "Dismiss")
@@ -21,6 +22,11 @@ export default {
2122
NcModal,
2223
NcButton,
2324
},
25+
computed: {
26+
multiline() {
27+
return Array.isArray(this.content)
28+
},
29+
},
2430
}
2531
</script>
2632

src/js/browser_notifications.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { showSimpleAlertModal } from "cookbook/js/modals"
2+
3+
export const requestPermission = async ({ justification }) => {
4+
5+
// Exit early if browser doesn't support notifications
6+
if (!("Notification" in window)) {
7+
return
8+
}
9+
10+
// Exit early if already granted
11+
if (Notification.permission === 'granted') {
12+
return
13+
}
14+
15+
await showSimpleAlertModal(justification)
16+
await Notification.requestPermission()
17+
}
18+
19+
export const notify = async (title, options) => {
20+
21+
// Exit early if browser doesn't support notifications
22+
if (!("Notification" in window)) {
23+
return
24+
}
25+
26+
// Try one more time to get permission (maybe the caller forgot to call
27+
// requestPermission first)
28+
// If it's still not granted, exit early
29+
if (Notification.permission !== 'granted' && (await Notification.requestPermission() !== 'granted')) {
30+
return
31+
}
32+
33+
const notification = new Notification(title, options)
34+
notification.addEventListener("error", (error) => {
35+
// eslint-disable-next-line no-console
36+
console.error("Error showing notification:", error)
37+
})
38+
}

0 commit comments

Comments
 (0)