From 5ce2dc1bb4ee93f7e5121f684f957eb99ead22b8 Mon Sep 17 00:00:00 2001 From: Kareem Olim Date: Sat, 19 Nov 2022 15:54:48 +0200 Subject: [PATCH] feat(plugin): Read all notifications button (#217) Co-authored-by: Ven --- src/api/ServerList.ts | 55 +++++++++++++++++ src/api/index.ts | 7 ++- src/plugins/apiServerList.ts | 42 +++++++++++++ src/plugins/readAllNotificationsButton.tsx | 71 ++++++++++++++++++++++ src/utils/constants.ts | 4 ++ src/utils/discord.ts | 6 +- src/webpack/common.tsx | 3 + 7 files changed, 186 insertions(+), 2 deletions(-) create mode 100644 src/api/ServerList.ts create mode 100644 src/plugins/apiServerList.ts create mode 100644 src/plugins/readAllNotificationsButton.tsx diff --git a/src/api/ServerList.ts b/src/api/ServerList.ts new file mode 100644 index 00000000..d3a9a110 --- /dev/null +++ b/src/api/ServerList.ts @@ -0,0 +1,55 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import Logger from "../utils/Logger"; + +const logger = new Logger("ServerListAPI"); + +export enum ServerListRenderPosition { + Above, + In, +} + +const renderFunctionsAbove = new Set(); +const renderFunctionsIn = new Set(); + +function getRenderFunctions(position: ServerListRenderPosition) { + return position === ServerListRenderPosition.Above ? renderFunctionsAbove : renderFunctionsIn; +} + +export function addServerListElement(position: ServerListRenderPosition, renderFunction: Function) { + getRenderFunctions(position).add(renderFunction); +} + +export function removeServerListElement(position: ServerListRenderPosition, renderFunction: Function) { + getRenderFunctions(position).delete(renderFunction); +} + +export const renderAll = (position: ServerListRenderPosition) => { + const ret: Array = []; + + for (const renderFunction of getRenderFunctions(position)) { + try { + ret.unshift(renderFunction()); + } catch (e) { + logger.error("Failed to render server list element:", e); + } + } + + return ret; +}; diff --git a/src/api/index.ts b/src/api/index.ts index bde4b3e7..98fc6a4a 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -22,6 +22,7 @@ import * as $DataStore from "./DataStore"; import * as $MessageAccessories from "./MessageAccessories"; import * as $MessageEventsAPI from "./MessageEvents"; import * as $Notices from "./Notices"; +import * as $ServerList from "./ServerList"; /** * An API allowing you to listen to Message Clicks or run your own logic @@ -62,5 +63,9 @@ const MessageAccessories = $MessageAccessories; * An API allowing you to add badges to user profiles */ const Badges = $Badges; +/** + * An API allowing you to add custom elements to the server list + */ +const ServerList = $ServerList; -export { Badges, Commands, DataStore, MessageAccessories, MessageEvents, Notices }; +export { Badges, Commands, DataStore, MessageAccessories, MessageEvents, Notices, ServerList }; diff --git a/src/plugins/apiServerList.ts b/src/plugins/apiServerList.ts new file mode 100644 index 00000000..134870e2 --- /dev/null +++ b/src/plugins/apiServerList.ts @@ -0,0 +1,42 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { Devs } from "../utils/constants"; +import definePlugin from "../utils/types"; + +export default definePlugin({ + name: "ServerListAPI", + authors: [Devs.kemo], + description: "Api required for plugins that modify the server list", + patches: [ + { + find: "Messages.DISCODO_DISABLED", + replacement: { + match: /(Messages\.DISCODO_DISABLED\);return)(.*?homeIcon.*?)(\}function)/, + replace: "$1[$2].concat(Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.Above))$3" + } + }, + { + find: "Messages.SERVERS", + replacement: { + match: /(Messages\.SERVERS,children:)(.+?default:return null\}\}\)\))/, + replace: "$1Vencord.Api.ServerList.renderAll(Vencord.Api.ServerList.ServerListRenderPosition.In).concat($2)" + } + } + ] +}); diff --git a/src/plugins/readAllNotificationsButton.tsx b/src/plugins/readAllNotificationsButton.tsx new file mode 100644 index 00000000..615702b4 --- /dev/null +++ b/src/plugins/readAllNotificationsButton.tsx @@ -0,0 +1,71 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2022 Vendicated and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "../api/ServerList"; +import { Devs } from "../utils/constants"; +import definePlugin from "../utils/types"; +import { Button, FluxDispatcher, GuildChannelStore, GuildStore, React, ReadStateStore } from "../webpack/common"; + +function onClick() { + const channels: Array = []; + + Object.values(GuildStore.getGuilds()).forEach(guild => { + GuildChannelStore.getChannels(guild.id).SELECTABLE.forEach((c: { channel: { id: string; }; }) => { + if (!ReadStateStore.hasUnread(c.channel.id)) return; + + channels.push({ + channelId: c.channel.id, + // messageId: c.channel?.lastMessageId, + messageId: ReadStateStore.lastMessageId(c.channel.id), + readStateType: 0 + }); + }); + }); + + FluxDispatcher.dispatch({ + type: "BULK_ACK", + context: "APP", + channels: channels + }); +} + +const ReadAllButton = () => ( + +); + +export default definePlugin({ + name: "ReadAllNotificationsButton", + description: "Read all server notifications with a single button click!", + authors: [Devs.kemo], + dependencies: ["ServerListAPI"], + + renderReadAllButton: () => , + + start() { + addServerListElement(ServerListRenderPosition.In, this.renderReadAllButton); + }, + + stop() { + removeServerListElement(ServerListRenderPosition.In, this.renderReadAllButton); + } +}); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 307de872..7f44ee0d 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -136,5 +136,9 @@ export const Devs = Object.freeze({ KraXen72: { name: "KraXen72", id: 379304073515499530n + }, + kemo: { + name: "kemo", + id: 299693897859465228n } }); diff --git a/src/utils/discord.ts b/src/utils/discord.ts index 75fb079c..7fc5064a 100644 --- a/src/utils/discord.ts +++ b/src/utils/discord.ts @@ -18,7 +18,7 @@ import { Guild } from "discord-types/general"; -import { ChannelStore, GuildStore,SelectedChannelStore } from "../webpack/common"; +import { ChannelStore, GuildStore, PrivateChannelsStore, SelectedChannelStore } from "../webpack/common"; export function getCurrentChannel() { return ChannelStore.getChannel(SelectedChannelStore.getChannelId()); @@ -27,3 +27,7 @@ export function getCurrentChannel() { export function getCurrentGuild(): Guild | undefined { return GuildStore.getGuild(getCurrentChannel()?.guild_id); } + +export function openPrivateChannel(userId: string) { + PrivateChannelsStore.openPrivateChannel(userId); +} diff --git a/src/webpack/common.tsx b/src/webpack/common.tsx index 9645172b..5853e566 100644 --- a/src/webpack/common.tsx +++ b/src/webpack/common.tsx @@ -34,6 +34,9 @@ export const ReactDOM: typeof import("react-dom") = lazyWebpack(filters.byProps( export const MessageStore = lazyWebpack(filters.byProps("getRawMessages")) as Omit & { getMessages(chanId: string): any; }; export const PermissionStore = lazyWebpack(filters.byProps("can", "getGuildPermissions")); +export const PrivateChannelsStore = lazyWebpack(filters.byProps("openPrivateChannel")); +export const GuildChannelStore = lazyWebpack(filters.byProps("getChannels")); +export const ReadStateStore = lazyWebpack(filters.byProps("lastMessageId")); export let GuildStore: Stores.GuildStore; export let UserStore: Stores.UserStore; export let SelectedChannelStore: Stores.SelectedChannelStore;