GreetStickerPicker: greet with stickers of your choice (#866)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
This commit is contained in:
parent
edc96387f5
commit
4d836524c1
2 changed files with 200 additions and 2 deletions
185
src/plugins/welcomeStickerPicker.tsx
Normal file
185
src/plugins/welcomeStickerPicker.tsx
Normal 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} />);
|
||||||
|
}
|
||||||
|
});
|
17
src/webpack/common/types/menu.d.ts
vendored
17
src/webpack/common/types/menu.d.ts
vendored
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue