diff --git a/src/plugins/callTimer.ts b/src/plugins/callTimer.ts
deleted file mode 100644
index 264e74bd7..000000000
--- 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 .
-*/
-
-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 000000000..40aa1608f
--- /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 .
+*/
+
+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
+
+ ;
+ },
+
+ 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
Connected for {formatDuration(time)}
;
+ }
+});