Plugin

SilentTyping

Hide that you are typing

Chat Privacy
index.tsx
Download

Source

src/plugins/silentTyping/index.tsx
1import { ChatBarButton, ChatBarButtonFactory } from "@api/ChatButtons";
2import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, sendBotMessage } from "@api/Commands";
3import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
4import { definePluginSettings } from "@api/Settings";
5import { Devs } from "@utils/constants";
6import definePlugin, { IconComponent, OptionType } from "@utils/types";
7import { FluxDispatcher, Menu, React } from "@webpack/common";
8
9const settings = definePluginSettings({
10 showIcon: {
11 type: OptionType.BOOLEAN,
12 default: false,
13 description: "Show an icon for toggling the plugin",
14 restartNeeded: true,
15 },
16 contextMenu: {
17 type: OptionType.BOOLEAN,
18 description: "Add option to toggle the functionality in the chat input context menu",
19 default: true
20 },
21 isEnabled: {
22 type: OptionType.BOOLEAN,
23 description: "Toggle functionality",
24 default: true,
25 }
26});
27
28function SilentTypingEnabledIcon() {
29 return (
30 <SilentTypingIcon>
31 <mask id="silent-typing-msg-mask">
32 <path fill="#fff" d="M0 0h24v24H0Z"></path>
33 <path stroke="#000" strokeWidth="5.99068" d="M0 24 24 0" transform="translate(-2, -3)"></path>
34 </mask>
35 <path fill="var(--status-danger)" d="m21.178 1.70703 1.414 1.414L4.12103 21.593l-1.414-1.415L21.178 1.70703Z" />
36 </SilentTypingIcon>
37 );
38}
39
40const SilentTypingIcon: IconComponent = ({ height = 20, width = 20, className, children }) => {
41 return (
42 <svg
43 width={width}
44 height={height}
45 className={className}
46 viewBox="0 0 24 24"
47 style={{ scale: "1.2" }}
48 >
49 <path fill="currentColor" mask="url(#silent-typing-msg-mask)" d="M18.333 15.556H1.667a1.667 1.667 0 0 1 -1.667 -1.667v-10a1.667 1.667 0 0 1 1.667 -1.667h16.667a1.667 1.667 0 0 1 1.667 1.667v10a1.667 1.667 0 0 1 -1.667 1.667M4.444 6.25V4.861a0.417 0.417 0 0 0 -0.417 -0.417H2.639a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417H5.973a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V4.861a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V6.25a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m-11.667 3.333V8.194a0.417 0.417 0 0 0 -0.417 -0.417H4.306a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417H7.639a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m3.333 0V8.194a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V9.583a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m-11.667 3.333v-1.389a0.417 0.417 0 0 0 -0.417 -0.417H2.639a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417m10 0v-1.389a0.417 0.417 0 0 0 -0.417 -0.417H5.973a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h8.056a0.417 0.417 0 0 0 0.417 -0.417m3.333 0v-1.389a0.417 0.417 0 0 0 -0.417 -0.417h-1.389a0.417 0.417 0 0 0 -0.417 0.417V12.917a0.417 0.417 0 0 0 0.417 0.417h1.389a0.417 0.417 0 0 0 0.417 -0.417" transform="translate(2, 3)" />
50 {children}
51 </svg>
52 );
53};
54
55const SilentTypingToggle: ChatBarButtonFactory = ({ isMainChat }) => {
56 const { isEnabled, showIcon } = settings.use(["isEnabled", "showIcon"]);
57 const toggle = () => settings.store.isEnabled = !settings.store.isEnabled;
58
59 if (!isMainChat || !showIcon) return null;
60
61 return (
62 <ChatBarButton
63 tooltip={isEnabled ? "Disable Silent Typing" : "Enable Silent Typing"}
64 onClick={toggle}
65 >
66 {isEnabled ? <SilentTypingEnabledIcon /> : <SilentTypingIcon />}
67 </ChatBarButton>
68 );
69};
70
71
72const ChatBarContextCheckbox: NavContextMenuPatchCallback = children => {
73 const { isEnabled, contextMenu } = settings.use(["isEnabled", "contextMenu"]);
74 if (!contextMenu) return;
75
76 const group = findGroupChildrenByChildId("submit-button", children);
77
78 if (!group) return;
79
80 const idx = group.findIndex(c => c?.props?.id === "submit-button");
81
82 group.splice(idx + 1, 0,
83 <Menu.MenuCheckboxItem
84 id="vc-silent-typing"
85 label="Enable Silent Typing"
86 checked={isEnabled}
87 action={() => settings.store.isEnabled = !settings.store.isEnabled}
88 />
89 );
90};
91
92
93export default definePlugin({
94 name: "SilentTyping",
95 authors: [Devs.Ven, Devs.Rini, Devs.ImBanana],
96 description: "Hide that you are typing",
97 tags: ["Chat", "Privacy"],
98 settings,
99
100 contextMenus: {
101 "textarea-context": ChatBarContextCheckbox
102 },
103
104 patches: [
105 {
106 find: &#039;.dispatch({type:"TYPING_START_LOCAL"&#039;,
107 replacement: {
108 match: /startTyping\(\i\){.+?},stop/,
109 replace: "startTyping:$self.startTyping,stop"
110 }
111 },
112 ],
113
114 commands: [{
115 name: "silenttype",
116 description: "Toggle whether you&#039;re hiding that you&#039;re typing or not.",
117 inputType: ApplicationCommandInputType.BUILT_IN,
118 options: [
119 {
120 name: "value",
121 description: "Whether to hide or not that you&#039;re typing (default is toggle)",
122 required: false,
123 type: ApplicationCommandOptionType.BOOLEAN,
124 },
125 ],
126 execute: async (args, ctx) => {
127 settings.store.isEnabled = !!findOption(args, "value", !settings.store.isEnabled);
128 sendBotMessage(ctx.channel.id, {
129 content: settings.store.isEnabled ? "Silent typing enabled!" : "Silent typing disabled!",
130 });
131 },
132 }],
133
134 async startTyping(channelId: string) {
135 if (settings.store.isEnabled) return;
136 FluxDispatcher.dispatch({ type: "TYPING_START_LOCAL", channelId });
137 },
138
139 chatBarButton: {
140 icon: SilentTypingIcon,
141 render: SilentTypingToggle
142 }
143});
144