From c2c6c9fccb3b94340037d2136d647817d0a1c916 Mon Sep 17 00:00:00 2001
From: Vendicated <vendicated@riseup.net>
Date: Fri, 25 Nov 2022 18:28:15 +0100
Subject: [PATCH] CallTimer: Fix lag

---
 src/plugins/callTimer.ts  | 116 --------------------------------------
 src/plugins/callTimer.tsx | 101 +++++++++++++++++++++++++++++++++
 2 files changed, 101 insertions(+), 116 deletions(-)
 delete mode 100644 src/plugins/callTimer.ts
 create mode 100644 src/plugins/callTimer.tsx

diff --git a/src/plugins/callTimer.ts b/src/plugins/callTimer.ts
deleted file mode 100644
index 264e74bd..00000000
--- a/src/plugins/callTimer.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Vencord, a modification for Discord's desktop app
- * Copyright (c) 2022 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 { Settings } from "../api/settings";
-import { Devs } from "../utils/constants";
-import definePlugin, { OptionType } from "../utils/types";
-import { FluxDispatcher } from "../webpack/common";
-
-export default definePlugin({
-    name: "CallTimer",
-    description: "Adds a timer to vcs",
-    authors: [Devs.Ven],
-
-    style: void 0 as HTMLStyleElement | undefined,
-    startTime: 0,
-    interval: void 0 as NodeJS.Timeout | undefined,
-
-    options: {
-        format: {
-            type: OptionType.SELECT,
-            description: "The timer format. This can be any valid moment.js format",
-            options: [
-                {
-                    label: "30d 23:00:42",
-                    value: "stopwatch",
-                    default: true
-                },
-                {
-                    label: "30d 23h 00m 42s",
-                    value: "human"
-                }
-            ]
-        }
-    },
-
-
-    formatDuration(ms: number) {
-        // here be dragons (moment fucking sucks)
-        const human = Settings.plugins.CallTimer.format === "human";
-
-        const format = (n: number) => human ? n : n.toString().padStart(2, "0");
-        const unit = (s: string) => human ? s : "";
-        const delim = human ? " " : ":";
-
-        // thx copilot
-        const d = Math.floor(ms / 86400000);
-        const h = Math.floor((ms % 86400000) / 3600000);
-        const m = Math.floor(((ms % 86400000) % 3600000) / 60000);
-        const s = Math.floor((((ms % 86400000) % 3600000) % 60000) / 1000);
-
-        let res = "";
-        if (d) res += `${d}d `;
-        if (h || res) res += `${format(h)}${unit("h")}${delim}`;
-        if (m || res || !human) res += `${format(m)}${unit("m")}${delim}`;
-        res += `${format(s)}${unit("s")}`;
-
-        return res;
-    },
-
-    setTimer(ms: number) {
-        if (!this.style) return;
-
-        this.style.textContent = `
-        [class*="connection-"] [class*="channel-"]::after {
-            content: "Connected for ${this.formatDuration(ms)}";
-            display: block;
-        }
-        `;
-    },
-
-    start() {
-        const style = this.style = document.createElement("style");
-        style.id = "VencordCallTimer";
-        document.head.appendChild(style);
-
-        this.setTimer(0);
-
-        this.handleRtcConnectionState = this.handleRtcConnectionState.bind(this);
-        FluxDispatcher.subscribe("RTC_CONNECTION_STATE", this.handleRtcConnectionState);
-    },
-
-    handleRtcConnectionState(e: { state: string; }) {
-        if (e.state === "RTC_CONNECTED" || e.state === "RTC_DISCONNECTED") {
-            clearInterval(this.interval);
-            if (e.state === "RTC_CONNECTED") {
-                this.startTime = Date.now();
-                this.interval = setInterval(
-                    () => this.setTimer(Math.round(Date.now() - this.startTime)),
-                    1000
-                );
-            } else this.startTime = 0;
-            this.setTimer(0);
-        }
-    },
-
-    stop() {
-        FluxDispatcher.unsubscribe("RTC_CONNECTION_STATE", this.handleRtcConnectionState);
-        this.style?.remove();
-        clearInterval(this.interval);
-    }
-});
diff --git a/src/plugins/callTimer.tsx b/src/plugins/callTimer.tsx
new file mode 100644
index 00000000..40aa1608
--- /dev/null
+++ b/src/plugins/callTimer.tsx
@@ -0,0 +1,101 @@
+/*
+ * Vencord, a modification for Discord's desktop app
+ * Copyright (c) 2022 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 { Settings } from "../api/settings";
+import ErrorBoundary from "../components/ErrorBoundary";
+import { Devs } from "../utils/constants";
+import definePlugin, { OptionType } from "../utils/types";
+import { React } from "../webpack/common";
+
+function formatDuration(ms: number) {
+    // here be dragons (moment fucking sucks)
+    const human = Settings.plugins.CallTimer.format === "human";
+
+    const format = (n: number) => human ? n : n.toString().padStart(2, "0");
+    const unit = (s: string) => human ? s : "";
+    const delim = human ? " " : ":";
+
+    // thx copilot
+    const d = Math.floor(ms / 86400000);
+    const h = Math.floor((ms % 86400000) / 3600000);
+    const m = Math.floor(((ms % 86400000) % 3600000) / 60000);
+    const s = Math.floor((((ms % 86400000) % 3600000) % 60000) / 1000);
+
+    let res = "";
+    if (d) res += `${d}d `;
+    if (h || res) res += `${format(h)}${unit("h")}${delim}`;
+    if (m || res || !human) res += `${format(m)}${unit("m")}${delim}`;
+    res += `${format(s)}${unit("s")}`;
+
+    return res;
+}
+
+export default definePlugin({
+    name: "CallTimer",
+    description: "Adds a timer to vcs",
+    authors: [Devs.Ven],
+
+    startTime: 0,
+    interval: void 0 as NodeJS.Timeout | undefined,
+
+    options: {
+        format: {
+            type: OptionType.SELECT,
+            description: "The timer format. This can be any valid moment.js format",
+            options: [
+                {
+                    label: "30d 23:00:42",
+                    value: "stopwatch",
+                    default: true
+                },
+                {
+                    label: "30d 23h 00m 42s",
+                    value: "human"
+                }
+            ]
+        }
+    },
+
+    patches: [{
+        find: ".renderConnectionStatus=",
+        replacement: {
+            match: /(?<=renderConnectionStatus=.+\(\)\.channel,children:)\w/,
+            replace: "[$&, Vencord.Plugins.plugins.CallTimer.renderTimer(this.props.channel.id)]"
+        }
+    }],
+    renderTimer(channelId: string) {
+        return <ErrorBoundary noop>
+            <this.Timer channelId={channelId} />
+        </ErrorBoundary>;
+    },
+
+    Timer({ channelId }: { channelId: string; }) {
+        const [time, setTime] = React.useState(0);
+        const startTime = React.useMemo(() => Date.now(), [channelId]);
+
+        React.useEffect(() => {
+            const interval = setInterval(() => setTime(Date.now() - startTime), 1000);
+            return () => {
+                clearInterval(interval);
+                setTime(0);
+            };
+        }, [channelId]);
+
+        return <p style={{ margin: 0 }}>Connected for {formatDuration(time)}</p>;
+    }
+});