Notifications: Block muted channels from push notifs.

This commit is contained in:
Paul 2021-06-25 12:37:59 +01:00
parent 21859e4c55
commit 994ef65200
10 changed files with 53 additions and 29 deletions

View file

@ -8,7 +8,7 @@ import { connectState } from "../../redux/connector";
import { Message, SYSTEM_USER_ID, User } from "revolt.js"; import { Message, SYSTEM_USER_ID, User } from "revolt.js";
import { NotificationOptions } from "../../redux/reducers/settings"; import { NotificationOptions } from "../../redux/reducers/settings";
import { Route, Switch, useHistory, useParams } from "react-router-dom"; 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 { interface Props {
options?: NotificationOptions; options?: NotificationOptions;
@ -49,13 +49,7 @@ function Notifier({ options, notifs }: Props) {
if (author?.relationship === Users.Relationship.Blocked) return; if (author?.relationship === Users.Relationship.Blocked) return;
const notifState = getNotificationState(notifs, channel); const notifState = getNotificationState(notifs, channel);
switch (notifState) { if (!shouldNotify(notifState, msg, client.user!._id)) return;
case 'muted':
case 'none': return;
case 'mention': {
if (!msg.mentions?.includes(client.user!._id)) return;
}
}
playSound('message'); playSound('message');
if (!showNotification) return; if (!showNotification) return;

View file

@ -1,4 +1,4 @@
import { Auth } from "revolt.js/dist/api/objects"; import type { Auth } from "revolt.js/dist/api/objects";
export interface AuthState { export interface AuthState {
accounts: { accounts: {

View file

@ -1,5 +1,5 @@
import { Language } from "../../context/Locale"; import { Language } from "../../context/Locale";
import { SyncUpdateAction } from "./sync"; import type { SyncUpdateAction } from "./sync";
export type LocaleAction = export type LocaleAction =
| { type: undefined } | { type: undefined }

View file

@ -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'; 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]; 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 = export type NotificationsAction =
| { type: undefined } | { type: undefined }
| { | {
@ -29,6 +42,7 @@ export type NotificationsAction =
type: "NOTIFICATIONS_REMOVE"; type: "NOTIFICATIONS_REMOVE";
key: string; key: string;
} }
| SyncUpdateAction
| { | {
type: "RESET"; type: "RESET";
}; };
@ -48,6 +62,8 @@ export function notifications(
const { [action.key]: _, ...newState } = state; const { [action.key]: _, ...newState } = state;
return newState; return newState;
} }
case "SYNC_UPDATE":
return action.update.notifications?.[1] ?? state;
case "RESET": case "RESET":
return {}; return {};
default: default:

View file

@ -1,4 +1,4 @@
import { MessageObject } from "../../context/revoltjs/util"; import type { MessageObject } from "../../context/revoltjs/util";
export enum QueueStatus { export enum QueueStatus {
SENDING = "sending", SENDING = "sending",

View file

@ -1,4 +1,4 @@
import { Core } from "revolt.js/dist/api/objects"; import type { Core } from "revolt.js/dist/api/objects";
export type ConfigAction = export type ConfigAction =
| { type: undefined } | { type: undefined }

View file

@ -1,7 +1,7 @@
import { filter } from "."; import { filter } from ".";
import { SyncUpdateAction } from "./sync"; import type { SyncUpdateAction } from "./sync";
import { Sounds } from "../../assets/sounds/Audio"; import type { Sounds } from "../../assets/sounds/Audio";
import { Theme, ThemeOptions } from "../../context/Theme"; import type { Theme, ThemeOptions } from "../../context/Theme";
import { setEmojiPack } from "../../components/common/Emoji"; import { setEmojiPack } from "../../components/common/Emoji";
export type SoundOptions = { export type SoundOptions = {

View file

@ -1,7 +1,7 @@
import { AppearanceOptions } from "./settings"; import type { AppearanceOptions } from "./settings";
import { Language } from "../../context/Locale"; import type { Language } from "../../context/Locale";
import { ThemeOptions } from "../../context/Theme"; import type { ThemeOptions } from "../../context/Theme";
import { Notifications } from "./notifications"; import type { Notifications } from "./notifications";
export type SyncKeys = "theme" | "appearance" | "locale" | "notifications"; export type SyncKeys = "theme" | "appearance" | "locale" | "notifications";

View file

@ -1,4 +1,4 @@
import { Sync } from "revolt.js/dist/api/objects"; import type { Sync } from "revolt.js/dist/api/objects";
export interface Unreads { export interface Unreads {
[key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>; [key: string]: Partial<Omit<Sync.ChannelUnread, "_id">>;

View file

@ -3,6 +3,9 @@ import { precacheAndRoute } from 'workbox-precaching'
import { Server } from 'revolt.js/dist/api/objects' import { Server } from 'revolt.js/dist/api/objects'
import { Channel, Message, User } from 'revolt.js' import { Channel, Message, User } from 'revolt.js'
import { IDBPDatabase, openDB } from 'idb' 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 declare let self: ServiceWorkerGlobalScope
@ -34,12 +37,18 @@ function decodeTime(id: string) {
return time; return time;
} }
const base_url = `https://autumn.revolt.chat`;
self.addEventListener("push", event => { self.addEventListener("push", event => {
async function process() { async function process() {
if (event.data === null) return; if (event.data === null) return;
let data: Message = event.data.json(); 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; let db: IDBPDatabase;
try { try {
// Match RevoltClient.tsx#L55 // Match RevoltClient.tsx#L55
@ -65,19 +74,24 @@ self.addEventListener("push", event => {
} }
} }
let channel = await get<Channel>('channels', data.channel);
let user = await get<User>('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; let image;
if (data.attachments) { if (data.attachments) {
let attachment = data.attachments[0]; let attachment = data.attachments[0];
if (attachment.metadata.type === "Image") { 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<Channel>('channels', data.channel);
let user = await get<User>('users', data.author);
let username = user?.username ?? data.author;
switch (channel?.channel_type) { switch (channel?.channel_type) {
case "SavedMessages": break; case "SavedMessages": break;
case "DirectMessage": title = `@${username}`; break; case "DirectMessage": title = `@${username}`; break;
@ -97,7 +111,7 @@ self.addEventListener("push", event => {
} }
await self.registration.showNotification(title, { 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, image,
body: typeof data.content === "string" ? data.content : JSON.stringify(data.content), body: typeof data.content === "string" ? data.content : JSON.stringify(data.content),
timestamp: decodeTime(data._id), timestamp: decodeTime(data._id),