diff options
-rw-r--r-- | src/plugins/pronoundb/contextmenu.tsx | 62 | ||||
-rw-r--r-- | src/plugins/pronoundb/index.ts | 15 | ||||
-rw-r--r-- | src/plugins/pronoundb/pronoundbUtils.ts | 43 | ||||
-rw-r--r-- | src/plugins/pronoundb/settings.tsx (renamed from src/plugins/pronoundb/settings.ts) | 15 | ||||
-rw-r--r-- | src/plugins/pronoundb/types.ts | 2 |
5 files changed, 131 insertions, 6 deletions
diff --git a/src/plugins/pronoundb/contextmenu.tsx b/src/plugins/pronoundb/contextmenu.tsx new file mode 100644 index 0000000..7f4127a --- /dev/null +++ b/src/plugins/pronoundb/contextmenu.tsx @@ -0,0 +1,62 @@ +/* + * Vencord, a modification for Discord's desktop app + * Copyright (c) 2023 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 <https://www.gnu.org/licenses/>. +*/ + +import { NavContextMenuPatchCallback } from "@api/ContextMenu"; +import { FluxDispatcher, Menu } from "@webpack/common"; +import { User } from "discord-types/general"; + +import { getLocalPronounOverrideNow, setLocalPronounOverride } from "./pronoundbUtils"; +import { PronounCode, PronounCodes, PronounMapping } from "./types"; + +export const PronounOverrideContextMenu: NavContextMenuPatchCallback = (children, { user }: { user: User; }) => () => { + const userId = user.id; + // We cannot useAwaiter here for some reason (probably because this is not a React component, and we sadly can also not return a custom component and use useAwaiter in there, since we are in a context menu), so we have to use the cached version, which should be fine since whenever we right click someone we probably have loaded their profile. + const selected = getLocalPronounOverrideNow(userId); + const action = (newOverride: PronounCode | null) => () => { + setLocalPronounOverride(userId, newOverride); + FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" }); + }; + console.log(selected); + children.push(<Menu.MenuGroup> + <Menu.MenuItem + id="pronoundb-override" + label="Set Pronouns" + > + {<Menu.MenuGroup> + { + ...PronounCodes.map(id => + <Menu.MenuRadioItem + checked={selected === id} + action={action(id)} + id={id} + label={PronounMapping[id]} + group="pronoundb-override-group"> + </Menu.MenuRadioItem>) + } + <Menu.MenuSeparator /> + <Menu.MenuRadioItem + checked={selected === null} + id={"null"} + action={action(null)} + label={"No override"} + group="pronoundb-override-group"> + </Menu.MenuRadioItem> + </Menu.MenuGroup>} + </Menu.MenuItem> + </Menu.MenuGroup>); +}; diff --git a/src/plugins/pronoundb/index.ts b/src/plugins/pronoundb/index.ts index 227e07d..a6c2009 100644 --- a/src/plugins/pronoundb/index.ts +++ b/src/plugins/pronoundb/index.ts @@ -1,6 +1,6 @@ /* * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors + * Copyright (c) 2022-2023 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 @@ -18,17 +18,19 @@ import "./styles.css"; +import { addContextMenuPatch, removeContextMenuPatch } from "@api/ContextMenu"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; import PronounsAboutComponent from "./components/PronounsAboutComponent"; import { CompactPronounsChatComponentWrapper, PronounsChatComponentWrapper } from "./components/PronounsChatComponent"; +import { PronounOverrideContextMenu } from "./contextmenu"; import { useProfilePronouns } from "./pronoundbUtils"; import { settings } from "./settings"; export default definePlugin({ name: "PronounDB", - authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven], + authors: [Devs.Tyman, Devs.TheKodeToad, Devs.Ven, Devs.nea], description: "Adds pronouns to user messages using pronoundb", patches: [ // Add next to username (compact mode) @@ -72,5 +74,12 @@ export default definePlugin({ // Re-export the components on the plugin object so it is easily accessible in patches PronounsChatComponentWrapper, CompactPronounsChatComponentWrapper, - useProfilePronouns + useProfilePronouns, + + start() { + addContextMenuPatch("user-context", PronounOverrideContextMenu); + }, + stop() { + removeContextMenuPatch("user-context", PronounOverrideContextMenu); + } }); diff --git a/src/plugins/pronoundb/pronoundbUtils.ts b/src/plugins/pronoundb/pronoundbUtils.ts index 6a1fb31..915312f 100644 --- a/src/plugins/pronoundb/pronoundbUtils.ts +++ b/src/plugins/pronoundb/pronoundbUtils.ts @@ -1,6 +1,6 @@ /* * Vencord, a modification for Discord's desktop app - * Copyright (c) 2022 Vendicated and contributors + * Copyright (c) 2022-2023 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 @@ -16,6 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { DataStore } from "@api/index"; import { Settings } from "@api/Settings"; import { VENCORD_USER_AGENT } from "@utils/constants"; import { debounce } from "@utils/debounce"; @@ -30,6 +31,8 @@ export const enum PronounsFormat { Capitalized = "CAPITALIZED" } +// A map of local overrides that have been accessed. +const overrideCache: Record<string, PronounCode | null> = {}; // A map of cached pronouns so the same request isn't sent twice const cache: Record<string, PronounCode> = {}; // A map of ids and callbacks that should be triggered on fetch @@ -46,8 +49,39 @@ const bulkFetch = debounce(async () => { } }); +function pronounOverrideKey(id: string): string { + return `pronoundb-local-override-${id}`; +} + +const pronounOverrideListKey = "pronoundb-local-override-list"; + +export async function clearAllLocalPronounOverrides(): Promise<number> { + const items = await DataStore.get(pronounOverrideListKey) || []; + await DataStore.delMany(items.map(pronounOverrideKey)); + await DataStore.del(pronounOverrideListKey); + return items.length; +} + +export async function setLocalPronounOverride(id: string, code: PronounCode | null): Promise<void> { + delete cache[id]; + overrideCache[id] = code; + await DataStore.update(pronounOverrideListKey, old => { + const s = old || []; + return s.includes(id) ? s : [...s, id]; + }); + await DataStore.set(pronounOverrideKey(id), code); +} + +export async function getLocalPronounOverride(id: string): Promise<PronounCode | null> { + return overrideCache[id] = ((await DataStore.get(pronounOverrideKey(id))) ?? null); +} + +export function getLocalPronounOverrideNow(id: string): PronounCode | null { + return (overrideCache[id]) ?? null; +} + export function useFormattedPronouns(id: string): string | null { - const [result] = useAwaiter(() => fetchPronouns(id), { + const [result] = useAwaiter(() => findPronouns(id), { fallbackValue: getCachedPronouns(id), onError: e => console.error("Fetching pronouns failed: ", e) }); @@ -74,6 +108,11 @@ export function getCachedPronouns(id: string): PronounCode | null { return cache[id] ?? null; } +// Find the pronouns for one id, checking for local overrides first +export async function findPronouns(id: string): Promise<PronounCode> { + return await getLocalPronounOverride(id) ?? await fetchPronouns(id); +} + // Fetches the pronouns for one id, returning a promise that resolves if it was cached, or once the request is completed export function fetchPronouns(id: string): Promise<PronounCode> { return new Promise(res => { diff --git a/src/plugins/pronoundb/settings.ts b/src/plugins/pronoundb/settings.tsx index 2bd8288..8ce05b6 100644 --- a/src/plugins/pronoundb/settings.ts +++ b/src/plugins/pronoundb/settings.tsx @@ -16,10 +16,12 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ +import { showNotification } from "@api/Notifications"; import { definePluginSettings } from "@api/Settings"; import { OptionType } from "@utils/types"; +import { Button } from "@webpack/common"; -import { PronounsFormat } from "./pronoundbUtils"; +import { clearAllLocalPronounOverrides, PronounsFormat } from "./pronoundbUtils"; export const settings = definePluginSettings({ pronounsFormat: { @@ -51,5 +53,16 @@ export const settings = definePluginSettings({ type: OptionType.BOOLEAN, description: "Show in profile", default: true + }, + clearAll: { + type: OptionType.COMPONENT, + description: "Local overrides", + component: () => <Button onClick={() => clearAllLocalPronounOverrides().then(count => showNotification({ + title: "Cleared all local pronoun overrides!", + body: `Deleted ${count} overrides`, + permanent: false, + }))}> + Clear all local overrides + </Button> } }); diff --git a/src/plugins/pronoundb/types.ts b/src/plugins/pronoundb/types.ts index 9cfd77c..32f19b4 100644 --- a/src/plugins/pronoundb/types.ts +++ b/src/plugins/pronoundb/types.ts @@ -54,3 +54,5 @@ export const PronounMapping = { avoid: "Avoid pronouns, use my name", unspecified: "Unspecified" } as const; + +export const PronounCodes = Object.keys(PronounMapping) as PronounCode[]; |