diff --git a/src/context/revoltjs/Notifications.tsx b/src/context/revoltjs/Notifications.tsx index f4c451a0..04d5c5f9 100644 --- a/src/context/revoltjs/Notifications.tsx +++ b/src/context/revoltjs/Notifications.tsx @@ -53,11 +53,7 @@ function Notifier({ options }: Props) { const message = useCallback( async (msg: Message) => { - if (msg.author_id === client.user!._id) return; if (msg.channel_id === channel_id && document.hasFocus()) return; - if (client.user!.status?.presence === Presence.Busy) return; - if (msg.author?.relationship === RelationshipStatus.Blocked) return; - if (!notifs.shouldNotify(msg)) return; playSound("message"); diff --git a/src/mobx/implementation notes b/src/mobx/implementation notes index 2c052c9e..36cefd3b 100644 --- a/src/mobx/implementation notes +++ b/src/mobx/implementation notes @@ -1,18 +1,16 @@ -need to have a way to dump or sync to local storage -need a way to rehydrate data stores split settings per account(?) multiple accounts need to be supported -oop + redux -> mobx migration (wipe existing redux data post-migration) -look into talking with other tabs to detect multiple instances -(also use this to tell the user to close all tabs before updating) + +> look into talking with other tabs to detect multiple instances +> (also use this to tell the user to close all tabs before updating) write new settings data structures for server-side -(deprecate existing API and replace with new endpoints?) +---- (deprecate existing API and replace with new endpoints?) alternatively: keep using current system and eventually migrate -or: handle both incoming types of data and keep newer version +or: handle both incoming types of data and keep newer version (v1_prefix) need to document these data structures -handle missing languages by falling back on en_GB provide state globally? perform all authentication from inside mobx mobx parent holds client information and prepares us for first render diff --git a/src/mobx/stores/NotificationOptions.ts b/src/mobx/stores/NotificationOptions.ts index 44e4ef4d..eb4ee908 100644 --- a/src/mobx/stores/NotificationOptions.ts +++ b/src/mobx/stores/NotificationOptions.ts @@ -1,4 +1,5 @@ import { action, computed, makeAutoObservable, ObservableMap } from "mobx"; +import { Presence, RelationshipStatus } from "revolt-api/types/Users"; import { Channel } from "revolt.js/dist/maps/Channels"; import { Message } from "revolt.js/dist/maps/Messages"; import { Server } from "revolt.js/dist/maps/Servers"; @@ -79,6 +80,11 @@ export default class NotificationOptions implements Store, Persistent { } } + /** + * Compute the actual notification state for a given Channel. + * @param channel Channel + * @returns Notification state + */ computeForChannel(channel: Channel) { if (this.channel.has(channel._id)) { return this.channel.get(channel._id); @@ -91,21 +97,46 @@ export default class NotificationOptions implements Store, Persistent { return DEFAULT_STATES[channel.channel_type]; } + /** + * Check whether an incoming message should notify the user. + * @param message Message + * @returns Whether it should notify the user + */ shouldNotify(message: Message) { - const state = this.computeForChannel(message.channel!); + // Make sure the author is not blocked. + if (message.author?.relationship === RelationshipStatus.Blocked) { + return false; + } - switch (state) { + // Check if the message was sent by us. + const user = message.client.user!; + if (message.author_id === user._id) { + return false; + } + + // Check whether we are busy. + if (user.status?.presence === Presence.Busy) { + return false; + } + + switch (this.computeForChannel(message.channel!)) { case "muted": case "none": + // Ignore if muted. return false; case "mention": - if (!message.mention_ids?.includes(message.client.user!._id)) - return false; + // Ignore if it doesn't mention us. + if (!message.mention_ids?.includes(user._id)) return false; } return true; } + /** + * Compute the notification state for a given server. + * @param server_id Server ID + * @returns Notification state + */ computeForServer(server_id: string) { if (this.server.has(server_id)) { return this.server.get(server_id); @@ -114,10 +145,20 @@ export default class NotificationOptions implements Store, Persistent { return DEFAULT_SERVER_STATE; } + /** + * Get the notification state of a channel. + * @param channel_id Channel ID + * @returns Notification state + */ getChannelState(channel_id: string) { return this.channel.get(channel_id); } + /** + * Set the notification state of a channel. + * @param channel_id Channel ID + * @param state Notification state + */ setChannelState(channel_id: string, state?: NotificationState) { if (state) { this.channel.set(channel_id, state); @@ -126,10 +167,20 @@ export default class NotificationOptions implements Store, Persistent { } } + /** + * Get the notification state of a server. + * @param server_id Server ID + * @returns Notification state + */ getServerState(server_id: string) { return this.server.get(server_id); } + /** + * Set the notification state of a server. + * @param server_id Server ID + * @param state Notification state + */ setServerState(server_id: string, state?: NotificationState) { if (state) { this.server.set(server_id, state); @@ -138,6 +189,11 @@ export default class NotificationOptions implements Store, Persistent { } } + /** + * Check whether a Channel or Server is muted. + * @param target Channel or Server + * @returns Whether this object is muted + */ isMuted(target?: Channel | Server) { if (target instanceof Channel) { return this.computeForChannel(target) === "muted";