From 60980df26ba158c5c184498c823f70df5ac06ec9 Mon Sep 17 00:00:00 2001
From: Philipp Heckel <pheckel@datto.com>
Date: Tue, 8 Mar 2022 16:56:41 -0500
Subject: [PATCH] Mute button

---
 web/src/app/Notifier.js            |  5 +++-
 web/src/app/SubscriptionManager.js |  7 ++++++
 web/src/components/ActionBar.js    | 38 ++++++++++++++++--------------
 web/src/components/Navigation.js   |  6 +++--
 4 files changed, 35 insertions(+), 21 deletions(-)

diff --git a/web/src/app/Notifier.js b/web/src/app/Notifier.js
index 5db6f487..10bfc50d 100644
--- a/web/src/app/Notifier.js
+++ b/web/src/app/Notifier.js
@@ -22,7 +22,7 @@ class Notifier {
         if (notification.click) {
             n.onclick = (e) => openUrl(notification.click);
         } else {
-            n.onclick = onClickFallback;
+            n.onclick = () => onClickFallback(subscription);
         }
 
         // Play sound
@@ -51,6 +51,9 @@ class Notifier {
     }
 
     async shouldNotify(subscription, notification) {
+        if (subscription.mutedUntil === 1) {
+            return false;
+        }
         const priority = (notification.priority) ? notification.priority : 3;
         const minPriority = await prefs.minPriority();
         if (priority < minPriority) {
diff --git a/web/src/app/SubscriptionManager.js b/web/src/app/SubscriptionManager.js
index 4b608f41..253acf17 100644
--- a/web/src/app/SubscriptionManager.js
+++ b/web/src/app/SubscriptionManager.js
@@ -23,6 +23,7 @@ class SubscriptionManager {
             baseUrl: baseUrl,
             topic: topic,
             ephemeral: ephemeral,
+            mutedUntil: 0,
             last: null
         };
         await db.subscriptions.put(subscription);
@@ -108,6 +109,12 @@ class SubscriptionManager {
             .modify({new: 0});
     }
 
+    async setMutedUntil(subscriptionId, mutedUntil) {
+        await db.subscriptions.update(subscriptionId, {
+            mutedUntil: mutedUntil
+        });
+    }
+
     async pruneNotifications(thresholdTimestamp) {
         await db.notifications
             .where("time").below(thresholdTimestamp)
diff --git a/web/src/components/ActionBar.js b/web/src/components/ActionBar.js
index a135a238..32b32d98 100644
--- a/web/src/components/ActionBar.js
+++ b/web/src/components/ActionBar.js
@@ -16,6 +16,8 @@ import Popper from '@mui/material/Popper';
 import MenuItem from '@mui/material/MenuItem';
 import MenuList from '@mui/material/MenuList';
 import MoreVertIcon from "@mui/icons-material/MoreVert";
+import NotificationsIcon from '@mui/icons-material/Notifications';
+import NotificationsOffIcon from '@mui/icons-material/NotificationsOff';
 import api from "../app/Api";
 import subscriptionManager from "../app/SubscriptionManager";
 
@@ -50,25 +52,32 @@ const ActionBar = (props) => {
                 <Typography variant="h6" noWrap component="div" sx={{ flexGrow: 1 }}>
                     {title}
                 </Typography>
-                {props.selected && <SettingsIcon
-                    subscription={props.selected}
-                    onUnsubscribe={props.onUnsubscribe}
-                />}
+                {props.selected &&
+                    <SettingsIcons
+                        subscription={props.selected}
+                        onUnsubscribe={props.onUnsubscribe}
+                    />}
             </Toolbar>
         </AppBar>
     );
 };
 
 // Originally from https://mui.com/components/menus/#MenuListComposition.js
-const SettingsIcon = (props) => {
+const SettingsIcons = (props) => {
     const navigate = useNavigate();
     const [open, setOpen] = useState(false);
     const anchorRef = useRef(null);
+    const subscription = props.subscription;
 
-    const handleToggle = () => {
+    const handleToggleOpen = () => {
         setOpen((prevOpen) => !prevOpen);
     };
 
+    const handleToggleMute = async () => {
+        const mutedUntil = (subscription.mutedUntil) ? 0 : 1; // Make this a timestamp in the future
+        await subscriptionManager.setMutedUntil(subscription.id, mutedUntil);
+    }
+
     const handleClose = (event) => {
         if (anchorRef.current && anchorRef.current.contains(event.target)) {
             return;
@@ -122,14 +131,10 @@ const SettingsIcon = (props) => {
 
     return (
         <>
-            <IconButton
-                color="inherit"
-                size="large"
-                edge="end"
-                ref={anchorRef}
-                id="composition-button"
-                onClick={handleToggle}
-            >
+            <IconButton color="inherit" size="large" edge="end" onClick={handleToggleMute} sx={{marginRight: 0}}>
+                {subscription.mutedUntil ? <NotificationsOffIcon/> : <NotificationsIcon/>}
+            </IconButton>
+            <IconButton color="inherit" size="large" edge="end" ref={anchorRef} onClick={handleToggleOpen}>
                 <MoreVertIcon/>
             </IconButton>
             <Popper
@@ -143,10 +148,7 @@ const SettingsIcon = (props) => {
                 {({TransitionProps, placement}) => (
                     <Grow
                         {...TransitionProps}
-                        style={{
-                            transformOrigin:
-                                placement === 'bottom-start' ? 'left top' : 'left bottom',
-                        }}
+                        style={{transformOrigin: placement === 'bottom-start' ? 'left top' : 'left bottom'}}
                     >
                         <Paper>
                             <ClickAwayListener onClickAway={handleClose}>
diff --git a/web/src/components/Navigation.js b/web/src/components/Navigation.js
index c49e533d..0cb1de0b 100644
--- a/web/src/components/Navigation.js
+++ b/web/src/components/Navigation.js
@@ -18,11 +18,11 @@ import {subscriptionRoute, topicShortUrl, topicUrl} from "../app/utils";
 import {ConnectionState} from "../app/Connection";
 import {useLocation, useNavigate} from "react-router-dom";
 import subscriptionManager from "../app/SubscriptionManager";
-import {ChatBubble} from "@mui/icons-material";
+import {ChatBubble, NotificationsOffOutlined} from "@mui/icons-material";
 import Box from "@mui/material/Box";
 import notifier from "../app/Notifier";
 
-const navWidth = 240;
+const navWidth = 280;
 
 const Navigation = (props) => {
     const navigationList = <NavList {...props}/>;
@@ -159,6 +159,8 @@ const SubscriptionItem = (props) => {
         <ListItemButton onClick={handleClick} selected={props.selected}>
             <ListItemIcon>{icon}</ListItemIcon>
             <ListItemText primary={label}/>
+            {subscription.mutedUntil > 0 &&
+                <ListItemIcon edge="end"><NotificationsOffOutlined /></ListItemIcon>}
         </ListItemButton>
     );
 };