2021-12-10 17:00:34 +00:00
|
|
|
import { action, computed, makeAutoObservable, ObservableMap } from "mobx";
|
2021-12-12 12:26:45 +00:00
|
|
|
import { Presence, RelationshipStatus } from "revolt-api/types/Users";
|
2021-12-11 23:34:46 +00:00
|
|
|
import { Channel } from "revolt.js/dist/maps/Channels";
|
|
|
|
import { Message } from "revolt.js/dist/maps/Messages";
|
|
|
|
import { Server } from "revolt.js/dist/maps/Servers";
|
2021-12-10 17:00:34 +00:00
|
|
|
|
2021-12-11 16:24:23 +00:00
|
|
|
import { mapToRecord } from "../../lib/conversion";
|
|
|
|
|
2021-12-24 02:05:18 +00:00
|
|
|
import {
|
|
|
|
legacyMigrateNotification,
|
|
|
|
LegacyNotifications,
|
|
|
|
} from "../legacy/redux";
|
|
|
|
|
|
|
|
import { MIGRATIONS } from "../State";
|
2021-12-11 14:36:26 +00:00
|
|
|
import Persistent from "../interfaces/Persistent";
|
2021-12-11 16:24:23 +00:00
|
|
|
import Store from "../interfaces/Store";
|
2021-12-24 02:05:18 +00:00
|
|
|
import Syncable from "../interfaces/Syncable";
|
2021-12-10 17:00:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Possible notification states.
|
|
|
|
* TODO: make "muted" gray out the channel
|
|
|
|
* TODO: add server defaults
|
|
|
|
*/
|
|
|
|
export type NotificationState = "all" | "mention" | "none" | "muted";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Default notification states for various types of channels.
|
|
|
|
*/
|
|
|
|
export const DEFAULT_STATES: {
|
|
|
|
[key in Channel["channel_type"]]: NotificationState;
|
|
|
|
} = {
|
|
|
|
SavedMessages: "all",
|
|
|
|
DirectMessage: "all",
|
|
|
|
Group: "all",
|
2021-12-11 23:34:46 +00:00
|
|
|
TextChannel: undefined!,
|
|
|
|
VoiceChannel: undefined!,
|
2021-12-10 17:00:34 +00:00
|
|
|
};
|
|
|
|
|
2021-12-11 23:34:46 +00:00
|
|
|
/**
|
|
|
|
* Default state for servers.
|
|
|
|
*/
|
|
|
|
export const DEFAULT_SERVER_STATE: NotificationState = "mention";
|
|
|
|
|
2021-12-21 12:31:14 +00:00
|
|
|
export interface Data {
|
2021-12-11 23:34:46 +00:00
|
|
|
server?: Record<string, NotificationState>;
|
|
|
|
channel?: Record<string, NotificationState>;
|
2021-12-10 17:00:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Manages the user's notification preferences.
|
|
|
|
*/
|
2021-12-24 02:05:18 +00:00
|
|
|
export default class NotificationOptions
|
|
|
|
implements Store, Persistent<Data>, Syncable
|
|
|
|
{
|
2021-12-11 23:34:46 +00:00
|
|
|
private server: ObservableMap<string, NotificationState>;
|
|
|
|
private channel: ObservableMap<string, NotificationState>;
|
2021-12-10 17:00:34 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Construct new Experiments store.
|
|
|
|
*/
|
|
|
|
constructor() {
|
|
|
|
this.server = new ObservableMap();
|
|
|
|
this.channel = new ObservableMap();
|
|
|
|
makeAutoObservable(this);
|
|
|
|
}
|
|
|
|
|
2021-12-11 16:24:23 +00:00
|
|
|
get id() {
|
|
|
|
return "notifications";
|
|
|
|
}
|
|
|
|
|
2021-12-10 17:00:34 +00:00
|
|
|
toJSON() {
|
|
|
|
return {
|
2021-12-11 16:24:23 +00:00
|
|
|
server: mapToRecord(this.server),
|
|
|
|
channel: mapToRecord(this.channel),
|
2021-12-10 17:00:34 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@action hydrate(data: Data) {
|
|
|
|
if (data.server) {
|
|
|
|
Object.keys(data.server).forEach((key) =>
|
|
|
|
this.server.set(key, data.server![key]),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.channel) {
|
|
|
|
Object.keys(data.channel).forEach((key) =>
|
|
|
|
this.channel.set(key, data.channel![key]),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Compute the actual notification state for a given Channel.
|
|
|
|
* @param channel Channel
|
|
|
|
* @returns Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
computeForChannel(channel: Channel) {
|
|
|
|
if (this.channel.has(channel._id)) {
|
|
|
|
return this.channel.get(channel._id);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel.server_id) {
|
|
|
|
return this.computeForServer(channel.server_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DEFAULT_STATES[channel.channel_type];
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Check whether an incoming message should notify the user.
|
|
|
|
* @param message Message
|
|
|
|
* @returns Whether it should notify the user
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
shouldNotify(message: Message) {
|
2021-12-12 12:26:45 +00:00
|
|
|
// Make sure the author is not blocked.
|
|
|
|
if (message.author?.relationship === RelationshipStatus.Blocked) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2021-12-11 23:34:46 +00:00
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
switch (this.computeForChannel(message.channel!)) {
|
2021-12-11 23:34:46 +00:00
|
|
|
case "muted":
|
|
|
|
case "none":
|
2021-12-12 12:26:45 +00:00
|
|
|
// Ignore if muted.
|
2021-12-11 23:34:46 +00:00
|
|
|
return false;
|
|
|
|
case "mention":
|
2021-12-12 12:26:45 +00:00
|
|
|
// Ignore if it doesn't mention us.
|
|
|
|
if (!message.mention_ids?.includes(user._id)) return false;
|
2021-12-11 23:34:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Compute the notification state for a given server.
|
|
|
|
* @param server_id Server ID
|
|
|
|
* @returns Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
computeForServer(server_id: string) {
|
|
|
|
if (this.server.has(server_id)) {
|
|
|
|
return this.server.get(server_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
return DEFAULT_SERVER_STATE;
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Get the notification state of a channel.
|
|
|
|
* @param channel_id Channel ID
|
|
|
|
* @returns Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
getChannelState(channel_id: string) {
|
|
|
|
return this.channel.get(channel_id);
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Set the notification state of a channel.
|
|
|
|
* @param channel_id Channel ID
|
|
|
|
* @param state Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
setChannelState(channel_id: string, state?: NotificationState) {
|
|
|
|
if (state) {
|
|
|
|
this.channel.set(channel_id, state);
|
|
|
|
} else {
|
|
|
|
this.channel.delete(channel_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Get the notification state of a server.
|
|
|
|
* @param server_id Server ID
|
|
|
|
* @returns Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
getServerState(server_id: string) {
|
|
|
|
return this.server.get(server_id);
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Set the notification state of a server.
|
|
|
|
* @param server_id Server ID
|
|
|
|
* @param state Notification state
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
setServerState(server_id: string, state?: NotificationState) {
|
|
|
|
if (state) {
|
|
|
|
this.server.set(server_id, state);
|
|
|
|
} else {
|
|
|
|
this.server.delete(server_id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-12 12:26:45 +00:00
|
|
|
/**
|
|
|
|
* Check whether a Channel or Server is muted.
|
|
|
|
* @param target Channel or Server
|
|
|
|
* @returns Whether this object is muted
|
|
|
|
*/
|
2021-12-11 23:34:46 +00:00
|
|
|
isMuted(target?: Channel | Server) {
|
2021-12-23 19:37:19 +00:00
|
|
|
var value: NotificationState | undefined;
|
2021-12-11 23:34:46 +00:00
|
|
|
if (target instanceof Channel) {
|
2021-12-23 19:37:19 +00:00
|
|
|
value = this.computeForChannel(target);
|
2021-12-11 23:34:46 +00:00
|
|
|
} else if (target instanceof Server) {
|
2021-12-23 19:37:19 +00:00
|
|
|
value = this.computeForServer(target._id);
|
2021-12-11 23:34:46 +00:00
|
|
|
}
|
2021-12-23 19:37:19 +00:00
|
|
|
|
|
|
|
if (value === "muted") {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2021-12-11 23:34:46 +00:00
|
|
|
}
|
2021-12-24 02:05:18 +00:00
|
|
|
|
|
|
|
@action apply(_key: "notifications", data: unknown, revision: number) {
|
|
|
|
if (revision < MIGRATIONS.REDUX) {
|
|
|
|
data = legacyMigrateNotification(data as LegacyNotifications);
|
|
|
|
}
|
|
|
|
|
|
|
|
this.hydrate(data as Data);
|
|
|
|
}
|
|
|
|
|
|
|
|
@computed toSyncable() {
|
|
|
|
return {
|
|
|
|
notifications: this.toJSON(),
|
|
|
|
};
|
|
|
|
}
|
2021-12-10 17:00:34 +00:00
|
|
|
}
|