Plugin

VoiceChatDoubleClick

Join voice chats via double click instead of single click

Voice
index.ts
Download

Source

src/plugins/vcDoubleClick/index.ts
1import { Devs } from "@utils/constants";
2import definePlugin from "@utils/types";
3import { ChannelStore, SelectedChannelStore } from "@webpack/common";
4
5const timers = {} as Record<string, {
6 timeout?: NodeJS.Timeout;
7 i: number;
8}>;
9
10export default definePlugin({
11 name: "VoiceChatDoubleClick",
12 description: "Join voice chats via double click instead of single click",
13 tags: ["Voice"],
14 authors: [Devs.Ven, Devs.D3SOX],
15 patches: [
16 // Stage Channels & Voice Channels
17 // the find is for stage channels, but it also handles voice
18 // channels because they're both in the same concatenated module
19 // the find for voice channels was `.handleVoiceStatusClick`
20 {
21 find: ".handleClickChat",
22 // hack: these are not React onClick, it is a custom prop handled by Discord
23 // thus, replacing this with onDoubleClick won't work, and you also cannot check
24 // e.detail since instead of the event they pass the channel.
25 // do this timer workaround instead
26 replacement: [
27 {
28 match: /onClick:\(\)=>\{this.handleClick\(\)/g,
29 replace: "onClick:()=>{$self.schedule(()=>{this.handleClick()},this)",
30 },
31 ]
32 },
33 {
34 // channel mentions
35 find: &#039;className:"channelMention",children:[null!=&#039;,
36 replacement: {
37 match: /onClick:(\i)(?=,.{0,30}className:"channelMention".+?(\i)\.inContent)/,
38 replace: (_, onClick, props) => ""
39 + `onClick:(vcDoubleClickEvt)=>$self.shouldRunOnClick(vcDoubleClickEvt,${props})&&${onClick}()`,
40 }
41 }
42 ],
43
44 shouldRunOnClick(e: MouseEvent, { channelId }) {
45 const channel = ChannelStore.getChannel(channelId);
46 if (!channel || ![2, 13].includes(channel.type)) return true;
47 return e.detail >= 2;
48 },
49
50 schedule(cb: () => void, e: any) {
51 const id = e.props.channel.id as string;
52 if (SelectedChannelStore.getVoiceChannelId() === id) {
53 cb();
54 return;
55 }
56 // use a different counter for each channel
57 const data = (timers[id] ??= { timeout: void 0, i: 0 });
58 // clear any existing timer
59 clearTimeout(data.timeout);
60
61 // if we already have 2 or more clicks, run the callback immediately
62 if (++data.i >= 2) {
63 cb();
64 delete timers[id];
65 } else {
66 // else reset the counter in 500ms
67 data.timeout = setTimeout(() => {
68 delete timers[id];
69 }, 500);
70 }
71 }
72});
73