diff --git a/src/plugins/callTimer/index.tsx b/src/plugins/callTimer/index.tsx index bf0bb1caa..1930e6334 100644 --- a/src/plugins/callTimer/index.tsx +++ b/src/plugins/callTimer/index.tsx @@ -20,6 +20,7 @@ import { definePluginSettings } from "@api/Settings"; import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { useTimer } from "@utils/react"; +import { formatDuration } from "@utils/text"; import definePlugin, { OptionType } from "@utils/types"; import { React } from "@webpack/common"; @@ -39,33 +40,10 @@ const settings = definePluginSettings({ label: "30d 23h 00m 42s", value: "human" } - ] + ] as const } }); -function formatDuration(ms: number) { - // here be dragons (moment fucking sucks) - const human = settings.store.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({ @@ -94,7 +72,7 @@ export default definePlugin({ return (

- {formatDuration(time)} + {formatDuration(time, settings.store.format === "human")}

); }, { noop: true }), diff --git a/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx b/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx index e091bda80..8038bbade 100644 --- a/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx +++ b/src/plugins/showHiddenChannels/components/HiddenChannelLockScreen.tsx @@ -22,7 +22,7 @@ import PermissionsViewerPlugin from "@plugins/permissionsViewer"; import openRolesAndUsersPermissionsModal from "@plugins/permissionsViewer/components/RolesAndUsersPermissions"; import { sortPermissionOverwrites } from "@plugins/permissionsViewer/utils"; import { classes } from "@utils/misc"; -import { formatDuration } from "@utils/text"; +import { formatDurationVerbose } from "@utils/text"; import type { Channel, RoleOrUserPermission } from "@vencord/discord-types"; import { findByPropsLazy, findComponentByCodeLazy, findCssClassesLazy } from "@webpack"; import { EmojiStore, FluxDispatcher, GuildMemberStore, GuildStore, Parser, PermissionsBits, PermissionStore, SnowflakeUtils, Text, Timestamp, Tooltip, useEffect, useState } from "@webpack/common"; @@ -204,11 +204,11 @@ function HiddenChannelLockScreen({ channel }: { channel: Channel; }) { Last message pin: } {(rateLimitPerUser ?? 0) > 0 && - Slowmode: {formatDuration(rateLimitPerUser!, "seconds")} + Slowmode: {formatDurationVerbose(rateLimitPerUser!, "seconds")} } {(defaultThreadRateLimitPerUser ?? 0) > 0 && - Default thread slowmode: {formatDuration(defaultThreadRateLimitPerUser!, "seconds")} + Default thread slowmode: {formatDurationVerbose(defaultThreadRateLimitPerUser!, "seconds")} } {((channel.isGuildVoice() || channel.isGuildStageVoice()) && bitrate != null) && @@ -223,7 +223,7 @@ function HiddenChannelLockScreen({ channel }: { channel: Channel; }) { {(defaultAutoArchiveDuration ?? 0) > 0 && Default inactivity duration before archiving {channel.isForumChannel() ? "posts" : "threads"}: - {" " + formatDuration(defaultAutoArchiveDuration!, "minutes")} + {" " + formatDurationVerbose(defaultAutoArchiveDuration!, "minutes")} } {defaultForumLayout != null && diff --git a/src/plugins/spotifyControls/PlayerComponent.tsx b/src/plugins/spotifyControls/PlayerComponent.tsx index 3074c5648..f52ff43ea 100644 --- a/src/plugins/spotifyControls/PlayerComponent.tsx +++ b/src/plugins/spotifyControls/PlayerComponent.tsx @@ -26,6 +26,7 @@ import { debounce } from "@shared/debounce"; import { classNameFactory } from "@utils/css"; import { copyWithToast, openImageModal } from "@utils/discord"; import { classes } from "@utils/misc"; +import { formatDuration } from "@utils/text"; import { ContextMenuApi, FluxDispatcher, Menu, React, useEffect, useState, useStateFromStores } from "@webpack/common"; import { settings } from "."; @@ -34,13 +35,6 @@ import { SpotifyStore, Track } from "./SpotifyStore"; const cl = classNameFactory("vc-spotify-"); -function msToHuman(ms: number) { - const minutes = ms / 1000 / 60; - const m = Math.floor(minutes); - const s = Math.floor((minutes - m) * 60); - return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`; -} - function Svg(path: string, label: string) { return () => ( - {msToHuman(position)} + {formatDuration(position)} - {msToHuman(duration)} + {formatDuration(duration)} ); diff --git a/src/utils/text.ts b/src/utils/text.ts index 385bfa0b7..538ecff6a 100644 --- a/src/utils/text.ts +++ b/src/utils/text.ts @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import { isTruthy } from "./guards"; + // Utils for readable text transformations eg: `toTitle(fromKebab())` // Case style to words @@ -51,7 +53,7 @@ function getUnitStr(unit: Units, isOne: boolean, short: boolean) { * @param unit The unit the time is on * @param short Whether to use short units like "d" instead of "days" */ -export function formatDuration(time: number, unit: Units, short: boolean = false) { +export function formatDurationVerbose(time: number, unit: Units, short: boolean = false) { const { moment } = require("@webpack/common") as typeof import("@webpack/common"); const dur = moment.duration(time, unit); @@ -93,6 +95,33 @@ export function formatDuration(time: number, unit: Units, short: boolean = false return res.length ? res : `0 ${getUnitStr(unit, false, short)}`; } +export function formatDuration(ms: number, human = false) { + const DAY = 86_400_000; + const HOUR = 3_600_000; + const MINUTE = 60_000; + + const days = Math.floor(ms / DAY); + const hours = Math.floor((ms % DAY) / HOUR); + const minutes = Math.floor((ms % HOUR) / MINUTE); + const seconds = Math.floor((ms % MINUTE) / 1000); + + const pad = (n: number) => human ? n : n.toString().padStart(2, "0"); + const unit = (s: string) => human ? s : ""; + + const showDays = days !== 0; + const showHours = showDays || hours !== 0; + const showMinutes = showHours || minutes !== 0 || !human; + + const duration = [ + showHours && `${pad(hours)}${unit("h")}`, + showMinutes && `${pad(minutes)}${unit("m")}`, + `${pad(seconds)}${unit("s")}` + ].filter(isTruthy).join(human ? " " : ":"); + + const prefix = showDays ? `${days}d ` : ""; + return prefix + duration; +} + /** * Join an array of strings in a human readable way (1, 2 and 3) * @param elements Elements