From 994ef652005f8b998e96ce5c6156d87a63d85856 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 25 Jun 2021 12:37:59 +0100 Subject: [PATCH] Notifications: Block muted channels from push notifs. --- src/context/revoltjs/Notifications.tsx | 10 ++------- src/redux/reducers/auth.ts | 2 +- src/redux/reducers/locale.ts | 2 +- src/redux/reducers/notifications.ts | 18 +++++++++++++++- src/redux/reducers/queue.ts | 2 +- src/redux/reducers/server_config.ts | 2 +- src/redux/reducers/settings.ts | 6 +++--- src/redux/reducers/sync.ts | 8 +++---- src/redux/reducers/unreads.ts | 2 +- src/sw.ts | 30 +++++++++++++++++++------- 10 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx index d9f4f1f9..7becc006 100644 --- a/src/context/revoltjs/Notifications.tsx +++ b/src/context/revoltjs/Notifications.tsx @@ -8,7 +8,7 @@ import { connectState } from "../../redux/connector"; import { Message, SYSTEM_USER_ID, User } from "revolt.js"; import { NotificationOptions } from "../../redux/reducers/settings"; import { Route, Switch, useHistory, useParams } from "react-router-dom"; -import { getNotificationState, Notifications } from "../../redux/reducers/notifications"; +import { getNotificationState, Notifications, shouldNotify } from "../../redux/reducers/notifications"; interface Props { options?: NotificationOptions; @@ -49,13 +49,7 @@ function Notifier({ options, notifs }: Props) { if (author?.relationship === Users.Relationship.Blocked) return; const notifState = getNotificationState(notifs, channel); - switch (notifState) { - case 'muted': - case 'none': return; - case 'mention': { - if (!msg.mentions?.includes(client.user!._id)) return; - } - } + if (!shouldNotify(notifState, msg, client.user!._id)) return; playSound('message'); if (!showNotification) return; diff --git a/src/redux/reducers/auth.ts b/src/redux/reducers/auth.ts index 38cd4df7..c309e4f8 100644 --- a/src/redux/reducers/auth.ts +++ b/src/redux/reducers/auth.ts @@ -1,4 +1,4 @@ -import { Auth } from "revolt.js/dist/api/objects"; +import type { Auth } from "revolt.js/dist/api/objects"; export interface AuthState { accounts: { diff --git a/src/redux/reducers/locale.ts b/src/redux/reducers/locale.ts index 416da63c..6146dd53 100644 --- a/src/redux/reducers/locale.ts +++ b/src/redux/reducers/locale.ts @@ -1,5 +1,5 @@ import { Language } from "../../context/Locale"; -import { SyncUpdateAction } from "./sync"; +import type { SyncUpdateAction } from "./sync"; export type LocaleAction = | { type: undefined } diff --git a/src/redux/reducers/notifications.ts b/src/redux/reducers/notifications.ts index 2ca5b030..6ffd352e 100644 --- a/src/redux/reducers/notifications.ts +++ b/src/redux/reducers/notifications.ts @@ -1,4 +1,5 @@ -import { Channel } from "revolt.js"; +import type { Channel, Message } from "revolt.js"; +import type { SyncUpdateAction } from "./sync"; export type NotificationState = 'all' | 'mention' | 'none' | 'muted'; @@ -18,6 +19,18 @@ export function getNotificationState(notifications: Notifications, channel: Chan return notifications[channel._id] ?? DEFAULT_STATES[channel.channel_type]; } +export function shouldNotify(state: NotificationState, message: Message, user_id: string) { + switch (state) { + case 'muted': + case 'none': return false; + case 'mention': { + if (!message.mentions?.includes(user_id)) return false; + } + } + + return true; +} + export type NotificationsAction = | { type: undefined } | { @@ -29,6 +42,7 @@ export type NotificationsAction = type: "NOTIFICATIONS_REMOVE"; key: string; } + | SyncUpdateAction | { type: "RESET"; }; @@ -48,6 +62,8 @@ export function notifications( const { [action.key]: _, ...newState } = state; return newState; } + case "SYNC_UPDATE": + return action.update.notifications?.[1] ?? state; case "RESET": return {}; default: diff --git a/src/redux/reducers/queue.ts b/src/redux/reducers/queue.ts index 3bcbec58..ef64578e 100644 --- a/src/redux/reducers/queue.ts +++ b/src/redux/reducers/queue.ts @@ -1,4 +1,4 @@ -import { MessageObject } from "../../context/revoltjs/util"; +import type { MessageObject } from "../../context/revoltjs/util"; export enum QueueStatus { SENDING = "sending", diff --git a/src/redux/reducers/server_config.ts b/src/redux/reducers/server_config.ts index 9e14fb0b..6046c5d1 100644 --- a/src/redux/reducers/server_config.ts +++ b/src/redux/reducers/server_config.ts @@ -1,4 +1,4 @@ -import { Core } from "revolt.js/dist/api/objects"; +import type { Core } from "revolt.js/dist/api/objects"; export type ConfigAction = | { type: undefined } diff --git a/src/redux/reducers/settings.ts b/src/redux/reducers/settings.ts index a37d7ef1..bd7e8220 100644 --- a/src/redux/reducers/settings.ts +++ b/src/redux/reducers/settings.ts @@ -1,7 +1,7 @@ import { filter } from "."; -import { SyncUpdateAction } from "./sync"; -import { Sounds } from "../../assets/sounds/Audio"; -import { Theme, ThemeOptions } from "../../context/Theme"; +import type { SyncUpdateAction } from "./sync"; +import type { Sounds } from "../../assets/sounds/Audio"; +import type { Theme, ThemeOptions } from "../../context/Theme"; import { setEmojiPack } from "../../components/common/Emoji"; export type SoundOptions = { diff --git a/src/redux/reducers/sync.ts b/src/redux/reducers/sync.ts index 0e2c8111..099d98d6 100644 --- a/src/redux/reducers/sync.ts +++ b/src/redux/reducers/sync.ts @@ -1,7 +1,7 @@ -import { AppearanceOptions } from "./settings"; -import { Language } from "../../context/Locale"; -import { ThemeOptions } from "../../context/Theme"; -import { Notifications } from "./notifications"; +import type { AppearanceOptions } from "./settings"; +import type { Language } from "../../context/Locale"; +import type { ThemeOptions } from "../../context/Theme"; +import type { Notifications } from "./notifications"; export type SyncKeys = "theme" | "appearance" | "locale" | "notifications"; diff --git a/src/redux/reducers/unreads.ts b/src/redux/reducers/unreads.ts index 290afdcb..1f1b2fb1 100644 --- a/src/redux/reducers/unreads.ts +++ b/src/redux/reducers/unreads.ts @@ -1,4 +1,4 @@ -import { Sync } from "revolt.js/dist/api/objects"; +import type { Sync } from "revolt.js/dist/api/objects"; export interface Unreads { [key: string]: Partial>; diff --git a/src/sw.ts b/src/sw.ts index 26848164..7d58aba3 100644 --- a/src/sw.ts +++ b/src/sw.ts @@ -3,6 +3,9 @@ import { precacheAndRoute } from 'workbox-precaching' import { Server } from 'revolt.js/dist/api/objects' import { Channel, Message, User } from 'revolt.js' import { IDBPDatabase, openDB } from 'idb' +import { getItem } from 'localforage' +import type { State } from './redux' +import { getNotificationState, shouldNotify } from './redux/reducers/notifications' declare let self: ServiceWorkerGlobalScope @@ -34,12 +37,18 @@ function decodeTime(id: string) { return time; } -const base_url = `https://autumn.revolt.chat`; self.addEventListener("push", event => { async function process() { if (event.data === null) return; let data: Message = event.data.json(); + let item = await localStorage.getItem('state'); + if (!item) return; + + const state: State = JSON.parse(item); + const autumn_url = state.config.features.autumn.url; + const user_id = state.auth.active!; + let db: IDBPDatabase; try { // Match RevoltClient.tsx#L55 @@ -65,19 +74,24 @@ self.addEventListener("push", event => { } } + let channel = await get('channels', data.channel); + let user = await get('users', data.author); + + if (channel) { + const notifs = getNotificationState(state.notifications, channel); + if (!shouldNotify(notifs, data, user_id)) return; + } + + let title = `@${data.author}`; + let username = user?.username ?? data.author; let image; if (data.attachments) { let attachment = data.attachments[0]; if (attachment.metadata.type === "Image") { - image = `${base_url}/${attachment.tag}/${attachment._id}`; + image = `${autumn_url}/${attachment.tag}/${attachment._id}`; } } - let title = `@${data.author}`; - let channel = await get('channels', data.channel); - let user = await get('users', data.author); - let username = user?.username ?? data.author; - switch (channel?.channel_type) { case "SavedMessages": break; case "DirectMessage": title = `@${username}`; break; @@ -97,7 +111,7 @@ self.addEventListener("push", event => { } await self.registration.showNotification(title, { - icon: user?.avatar ? `${base_url}/${user.avatar.tag}/${user.avatar._id}` : `https://api.revolt.chat/users/${data.author}/default_avatar`, + icon: user?.avatar ? `${autumn_url}/${user.avatar.tag}/${user.avatar._id}` : `https://api.revolt.chat/users/${data.author}/default_avatar`, image, body: typeof data.content === "string" ? data.content : JSON.stringify(data.content), timestamp: decodeTime(data._id),