aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorB. Stack <bgstack15@gmail.com>2023-11-10 17:12:41 -0500
committerB. Stack <bgstack15@gmail.com>2023-11-10 17:12:41 -0500
commit6bb4b9a5600dc7278acee769f3dc4a6be0296229 (patch)
tree6e49d1f702b332a65957e3c239062a2f342f30b6
parentadd build-rpm.sh (diff)
downloadradicaleinfcloud-6bb4b9a5600dc7278acee769f3dc4a6be0296229.tar.gz
radicaleinfcloud-6bb4b9a5600dc7278acee769f3dc4a6be0296229.tar.bz2
radicaleinfcloud-6bb4b9a5600dc7278acee769f3dc4a6be0296229.zip
add desktop notifications
Use the calendar color for the icon, if it is defined. Event-specific color is not supported at this time.
-rw-r--r--radicale_infcloud/web/data_process.js9
-rw-r--r--radicale_infcloud/web/index.html2
-rw-r--r--radicale_infcloud/web/interface.js1
-rw-r--r--radicale_infcloud/web/notifications.js127
4 files changed, 138 insertions, 1 deletions
diff --git a/radicale_infcloud/web/data_process.js b/radicale_infcloud/web/data_process.js
index 69f81d4..d0cf40e 100644
--- a/radicale_infcloud/web/data_process.js
+++ b/radicale_infcloud/web/data_process.js
@@ -165,6 +165,7 @@ function setAlertTimeouts(isTodo, alertTime, dateStart, dateEnd, params, firstIn
if(aTime!==''&&aTime>now)
{
var delay=aTime-now;
+ var this_color = "";
if(maxAlarmValue<delay)
delay=maxAlarmValue;
if(isTodo)
@@ -173,7 +174,13 @@ function setAlertTimeouts(isTodo, alertTime, dateStart, dateEnd, params, firstIn
}, delay,startTime);
else
alertTimeOut[alertTimeOut.length]=setTimeout(function(startTime){
- showAlertEvents(uid, (aTime-now), {start:new Date(startTime.getTime()), allDay:params.allDay, title:params.title});
+ var collections=globalResourceCalDAVList.collections;
+ for(var i=0;i<collections.length;i++) {
+ if(uid.startsWith(collections[i].uid)) {
+ this_color = collections[i].ecolor;
+ }
+ }
+ showAlertEvents(uid, (aTime-now), {start:new Date(startTime.getTime()), allDay:params.allDay, title:params.title, color:this_color});
}, delay,startTime);
}
}
diff --git a/radicale_infcloud/web/index.html b/radicale_infcloud/web/index.html
index a0c8fd6..75af8ee 100644
--- a/radicale_infcloud/web/index.html
+++ b/radicale_infcloud/web/index.html
@@ -60,6 +60,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script src="main.js" type="text/javascript"></script>
<script src="forms.js" type="text/javascript"></script>
<script src="timezones.js" type="text/javascript"></script>
+ <script src="notifications.js" type="text/javascript"></script>
</head>
<body>
<div id="cacheDialog">
@@ -143,6 +144,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<tr><td><kbd>Ctrl</kbd><kbd>3</kbd></td><td>Week view</td></tr>
<tr><td><kbd>Ctrl</kbd><kbd>4</kbd></td><td>Day view</td></tr>
</table>
+ <button id="testNotification" onclick="clickTestNotification()">Send test notification</button>
</div>
<div id="aboutDialog" title="About dialog">
<div id="aboutCloseButton">x</div>
diff --git a/radicale_infcloud/web/interface.js b/radicale_infcloud/web/interface.js
index 7f7304b..d98860d 100644
--- a/radicale_infcloud/web/interface.js
+++ b/radicale_infcloud/web/interface.js
@@ -1215,6 +1215,7 @@ function showAlertEvents(inputUID, realDelay, alarmObject)
timeString=' - '+timeS;
}
+ SendColorizedNotification(alarmObject.title,timeString,img_cal,"",alarmObject.color);
$('#alertBoxContent').append("<div class='alert_item'><img src='images/calendarB.svg' alt='Calendar'/><label>"+alarmObject.title+dateString+timeString+"</label></div>");
}
}
diff --git a/radicale_infcloud/web/notifications.js b/radicale_infcloud/web/notifications.js
new file mode 100644
index 0000000..06670a5
--- /dev/null
+++ b/radicale_infcloud/web/notifications.js
@@ -0,0 +1,127 @@
+/*
+vim: set et ts=3 sw=3 sts=3:
+InfCloud - the open source CalDAV/CardDAV Web Client
+Copyright (C) 2011-2023
+ B. Stack <bgstack15@gmail.com>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+// InfCloud/CalDAVZap location for this image
+const img_cal = "images/banner_calendar.svg";
+const notification_attempts = 10;
+const notification_ms = 200;
+// Due to how browsers/css work with colors, you can pass #000000 or web safe color names.
+var colors = Array("red","orange","yellow","green","blue","purple","black","white","brown");
+
+function colorizeSvg(inSvg, oldColor, newColor) {
+ // In case we have to do more than `s//g` in the future.
+ return inSvg.replaceAll(oldColor, newColor);
+}
+
+function SendColorizedNotification(_title, _body, _icon, _tag, _color) {
+ // given _icon as path on server, get contents and adjust the main color in it to desired color.
+ // The 585858 is the specific color of the calendar.svg we intend to replace.
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET",_icon);
+ xhr.onload = () => {
+ // Ref: https://stackoverflow.com/questions/28450471/convert-inline-svg-to-base64-string
+ newSvg = colorizeSvg(xhr.responseText,"#585858",_color);
+ encodedData = window.btoa(newSvg); // turn it into the base64 stream
+ encodedData = "data:image/svg+xml;base64," + encodedData; // prepend the type of stream
+ SendNotification(_title, _body, encodedData, _tag, _color);
+ }
+ xhr.send();
+}
+
+function SendNotification(_title, _body, _icon, _tag) {
+ // From: https://developer.mozilla.org/en-US/docs/Web/API/notification
+ if (!("Notification" in window)) {
+ // Check if the browser supports notifications
+ alert("This browser does not support desktop notification");
+ } else if (Notification.permission === "granted") {
+ // Check whether notification permissions have already been granted;
+ // if so, create a notification
+ console.log("trying option 1");
+ const notification = new Notification(String(_title), { tag: _tag, body: _body, icon: _icon });
+ // …
+ } else if (Notification.permission !== "denied") {
+ // We need to ask the user for permission
+ Notification.requestPermission().then((permission) => {
+ // If the user accepts, let's create a notification
+ if (permission === "granted") {
+ console.log("trying option 2");
+ const notification = new Notification(String(_title), { tag: _tag, body: _body, icon: _icon });
+ // …
+ }
+ });
+ }
+ // At last, if the user has denied notifications, and you
+ // want to be respectful there is no need to bother them anymore.
+ console.log("trying option 3");
+}
+
+function SendNotificationManyTimes(_title, _body, _icon, _tag) {
+ // From: https://developer.mozilla.org/en-US/docs/Web/API/Notifications_API/Using_the_Notifications_API
+ if (Notification?.permission === "granted") {
+ // If the user agreed to get notified
+ // Let's try to send ten notifications
+ let i = 0;
+ // Using an interval cause some browsers (including Firefox) are blocking notifications if there are too much in a certain time.
+ const interval = setInterval(() => {
+ // Thanks to the tag, we should only see the "Hi! 9" notification
+ const n = new Notification(String(_title), { tag: _tag, body: _body, icon: _icon });
+ //const n = new Notification(`Hi! breakfast ${i}`, { tag: "soManyNotification", body: "this is body?", icon: img });
+ if (i === (notification_attempts-1)) {
+ clearInterval(interval);
+ }
+ i++;
+ }, notification_ms);
+ } else if (Notification && Notification.permission !== "denied") {
+ // If the user hasn't told if they want to be notified or not
+ // Note: because of Chrome, we are not sure the permission property
+ // is set, therefore it's unsafe to check for the "default" value.
+ Notification.requestPermission().then((status) => {
+ // If the user said okay
+ if (status === "granted") {
+ let i = 0;
+ // Using an interval cause some browsers (including Firefox) are blocking notifications if there are too much in a certain time.
+ const interval = setInterval(() => {
+ // Thanks to the tag, we should only see the "Hi! 9" notification
+ const n = new Notification(String(_title), { tag: _tag, body: _body, icon: _icon });
+ if (i === (notification_attempts-1)) {
+ clearInterval(interval);
+ }
+ i++;
+ }, notification_ms);
+ } else {
+ // Otherwise, we can fallback to a regular modal alert
+ alert(String(_title)+": "+String(_body));
+ }
+ });
+ } else {
+ // If the user refuses to get notified, we can fallback to a regular modal alert
+ alert(String(_title)+": "+String(_body));
+ }
+}
+
+function getRandomColor() {
+ return colors[Math.floor(Math.random()*colors.length)];
+}
+
+function clickTestNotification()
+{
+ console.log("inside the click listener function");
+ SendColorizedNotification("sample calendar appointment","in 0 minutes",img_cal,"",getRandomColor());
+}
bgstack15