diff --git a/src/equicordplugins/customStatusTimeouts/index.tsx b/src/equicordplugins/customStatusTimeouts/index.tsx new file mode 100644 index 000000000..90b8eed4b --- /dev/null +++ b/src/equicordplugins/customStatusTimeouts/index.tsx @@ -0,0 +1,115 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2026 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import { EquicordDevs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const Millis = { + HALF_SECOND: 500, + SECOND: 1e3, + MINUTE: 6e4, + HOUR: 36e5, + DAY: 864e5, + WEEK: 6048e5, + DAYS_30: 2592e6 +}; + +const settings = definePluginSettings({ + showForeverOnTop: { + type: OptionType.BOOLEAN, + description: "Show the Forever option at the top of the list instead of the bottom.", + restartNeeded: true, + default: true + }, + extraSeconds: { + type: OptionType.STRING, + description: "Extra seconds to add, separated by a comma (e.g. 5, 10, 30)", + restartNeeded: true, + default: "15, 30, 45" + }, + extraMinutes: { + type: OptionType.STRING, + description: "Extra minutes to add, separated by a comma (e.g. 5, 10, 30)", + restartNeeded: true, + default: "5, 10, 30" + }, + extraHours: { + type: OptionType.STRING, + description: "Extra hours to add, separated by a comma (e.g. 2, 4, 6, 12)", + restartNeeded: true, + default: "2, 4, 6, 12" + }, + extraDays: { + type: OptionType.STRING, + description: "Extra days to add, separated by a comma (e.g. 1, 2)", + restartNeeded: true, + default: "1, 2" + }, +}); + +export default definePlugin({ + name: "CustomStatusTimeouts", + description: "Adds configurable timeout presets to the status (presence) menu.", + authors: [EquicordDevs.Kiri, EquicordDevs.thororen], + settings, + patches: [ + { + find: "#{intl::DURATION_FOREVER}", + replacement: { + match: /\[\{duration.*?#{intl::DURATION_FOREVER}\)\}\]/, + replace: "$self.buildTimeouts($&)" + } + } + ], + buildTimeouts(existing) { + const parse = (str: string) => str.split(",").map(s => Number(s.trim())).filter(Boolean); + + const seconds = parse(settings.store.extraSeconds); + const minutes = parse(settings.store.extraMinutes); + const hours = parse(settings.store.extraHours); + const days = parse(settings.store.extraDays); + // I was testing weeks and months and for some reason random ones didnt apply look below for the working ones + // tested weeks between 1-12 working weeks were 1, 2, 3, 8, 9, 10 the rest didnt work + // tested months between 1-12 working months were 2, 4, 10, 12 the rest didnt work + // for months I only tested evens except for 1 so I hardcoded them to avoid user complaints + const weeks = [1, 2, 3]; + const months = [2, 4]; + + const extra = [ + ...seconds.map(s => ({ + duration: s * Millis.SECOND, + label: () => `For ${s} ${s === 1 ? "Second" : "Seconds"}` + })), + ...minutes.map(m => ({ + duration: m * Millis.MINUTE, + label: () => `For ${m} ${m === 1 ? "Minute" : "Minutes"}` + })), + ...hours.map(h => ({ + duration: h * Millis.HOUR, + label: () => `For ${h} ${h === 1 ? "Hour" : "Hours"}` + })), + ...days.map(d => ({ + duration: d * Millis.DAY, + label: () => `For ${d} ${d === 1 ? "Day" : "Days"}` + })), + ...weeks.map(w => ({ + duration: w * Millis.WEEK, + label: () => `For ${w} ${w === 1 ? "Week" : "Weeks"}` + })), + ...months.map(m => ({ + duration: m * Millis.DAYS_30, + label: () => `For ${m} ${m === 1 ? "Month" : "Months"}` + })), + ]; + + return [...existing, ...extra].sort((a, b) => { + if (a.duration === undefined) return settings.store.showForeverOnTop ? -1 : 1; + if (b.duration === undefined) return settings.store.showForeverOnTop ? 1 : -1; + return a.duration - b.duration; + }); + } +}); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 1540f350b..96f90bd78 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -1284,6 +1284,10 @@ export const EquicordDevs = Object.freeze({ name: "Ape", id: 722832640360841308n, }, + Kiri: { + name: "Kiri", + id: 310525496771346434n, + }, } satisfies Record); // iife so #__PURE__ works correctly