GreetStickerPicker: greet with stickers of your choice (#866)

Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
V 2023-04-12 02:33:51 +02:00 committed by GitHub
parent edc96387f5
commit 4d836524c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 200 additions and 2 deletions

View file

@ -0,0 +1,185 @@
/*
* 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 { definePluginSettings } from "@api/settings";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { ContextMenu, FluxDispatcher, Menu } from "@webpack/common";
import { Channel, Message } from "discord-types/general";
interface Sticker {
id: string;
format_type: number;
description: string;
name: string;
}
enum GreetMode {
Greet = "Greet",
NormalMessage = "Message"
}
const settings = definePluginSettings({
greetMode: {
type: OptionType.SELECT,
options: [
{ label: "Greet (you can only greet 3 times)", value: GreetMode.Greet, default: true },
{ label: "Normal Message (you can greet spam)", value: GreetMode.NormalMessage }
],
description: "Choose the greet mode"
}
});
const MessageActions = findByPropsLazy("sendGreetMessage");
function greet(channel: Channel, message: Message, stickers: string[]) {
const options = MessageActions.getSendMessageOptionsForReply({
channel,
message,
shouldMention: true,
showMentionToggle: true
});
if (settings.store.greetMode === GreetMode.NormalMessage || stickers.length > 1) {
options.stickerIds = stickers;
const msg = {
content: "",
tts: false,
invalidEmojis: [],
validNonShortcutEmojis: []
};
MessageActions._sendMessage(channel.id, msg, options);
} else {
MessageActions.sendGreetMessage(channel.id, stickers[0], options);
}
}
function GreetMenu({ stickers, channel, message }: { stickers: Sticker[], message: Message, channel: Channel; }) {
const s = settings.use(["greetMode", "multiGreetChoices"] as any) as { greetMode: GreetMode, multiGreetChoices: string[]; };
const { greetMode, multiGreetChoices = [] } = s;
return (
<Menu.Menu
navId="greet-sticker-picker"
onClose={() => FluxDispatcher.dispatch({ type: "CONTEXT_MENU_CLOSE" })}
aria-label="Greet Sticker Picker"
>
<Menu.MenuGroup
label="Greet Mode"
>
{Object.values(GreetMode).map(mode => (
<Menu.MenuRadioItem
key={mode}
group="greet-mode"
id={"greet-mode-" + mode}
label={mode}
checked={mode === greetMode}
action={() => s.greetMode = mode}
/>
))}
</Menu.MenuGroup>
<Menu.MenuSeparator />
<Menu.MenuGroup
label="Greet Stickers"
>
{stickers.map(sticker => (
<Menu.MenuItem
key={sticker.id}
id={"greet-" + sticker.id}
label={sticker.description.split(" ")[0]}
action={() => greet(channel, message, [sticker.id])}
/>
))}
</Menu.MenuGroup>
{!(settings.store as any).unholyMultiGreetEnabled ? null : (
<>
<Menu.MenuSeparator />
<Menu.MenuItem
label="Unholy Multi-Greet"
id="unholy-multi-greet"
>
{stickers.map(sticker => {
const checked = multiGreetChoices.some(s => s === sticker.id);
return (
<Menu.MenuCheckboxItem
key={sticker.id}
id={"multi-greet-" + sticker.id}
label={sticker.description.split(" ")[0]}
checked={checked}
disabled={!checked && multiGreetChoices.length >= 3}
action={() => {
s.multiGreetChoices = checked
? multiGreetChoices.filter(s => s !== sticker.id)
: [...multiGreetChoices, sticker.id];
}}
/>
);
})}
<Menu.MenuSeparator />
<Menu.MenuItem
id="multi-greet-submit"
label="Send Greets"
action={() => greet(channel, message, multiGreetChoices!)}
disabled={multiGreetChoices.length === 0}
/>
</Menu.MenuItem>
</>
)}
</Menu.Menu>
);
}
export default definePlugin({
name: "GreetStickerPicker",
description: "Allows you to use any greet sticker instead of only the random one by right-clicking the 'Wave to say hi!' button",
authors: [Devs.Ven],
settings,
patches: [
{
find: "Messages.WELCOME_CTA_LABEL",
replacement: {
match: /innerClassName:\i\(\).welcomeCTAButton,(?<=%\i\.length;return (\i)\[\i\].+?)/,
replace: "$&onContextMenu:(e)=>$self.pickSticker(e,$1,arguments[0]),"
}
}
],
pickSticker(
event: React.UIEvent,
stickers: Sticker[],
props: {
channel: Channel,
message: Message;
}
) {
if (!(props.message as any).deleted)
ContextMenu.open(event, () => <GreetMenu stickers={stickers} {...props} />);
}
});

View file

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import type { ComponentType, CSSProperties, PropsWithChildren, UIEvent } from "react"; import type { ComponentType, CSSProperties, MouseEvent, PropsWithChildren, UIEvent } from "react";
type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>; type RC<C> = ComponentType<PropsWithChildren<C & Record<string, any>>>;
@ -30,10 +30,14 @@ export interface Menu {
onSelect?(): void; onSelect?(): void;
}>; }>;
MenuSeparator: ComponentType; MenuSeparator: ComponentType;
MenuGroup: RC<any>; MenuGroup: RC<{
label?: string;
}>;
MenuItem: RC<{ MenuItem: RC<{
id: string; id: string;
label: string; label: string;
action?(e: MouseEvent): void;
render?: ComponentType; render?: ComponentType;
onChildrenScroll?: Function; onChildrenScroll?: Function;
childRowHeight?: number; childRowHeight?: number;
@ -41,9 +45,18 @@ export interface Menu {
}>; }>;
MenuCheckboxItem: RC<{ MenuCheckboxItem: RC<{
id: string; id: string;
label: string;
checked: boolean;
action?(e: MouseEvent): void;
disabled?: boolean;
}>; }>;
MenuRadioItem: RC<{ MenuRadioItem: RC<{
id: string; id: string;
group: string;
label: string;
checked: boolean;
action?(e: MouseEvent): void;
disabled?: boolean;
}>; }>;
MenuControlItem: RC<{ MenuControlItem: RC<{
id: string; id: string;