mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-09 06:33:03 -04:00
Merge remote-tracking branch 'upstream/dev'
This commit is contained in:
commit
75433e88d9
7 changed files with 140 additions and 11 deletions
|
@ -156,7 +156,7 @@ ${makeCodeblock(enabledPlugins.join(", "))}
|
||||||
const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles;
|
const roles = GuildMemberStore.getSelfMember(VENCORD_GUILD_ID)?.roles;
|
||||||
if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return;
|
if (!roles || TrustedRolesIds.some(id => roles.includes(id))) return;
|
||||||
|
|
||||||
if (IS_UPDATER_DISABLED) {
|
if (!IS_WEB && IS_UPDATER_DISABLED) {
|
||||||
return Alerts.show({
|
return Alerts.show({
|
||||||
title: "Hold on!",
|
title: "Hold on!",
|
||||||
body: <div>
|
body: <div>
|
||||||
|
|
|
@ -6,17 +6,18 @@
|
||||||
|
|
||||||
import { definePluginSettings } from "@api/Settings";
|
import { definePluginSettings } from "@api/Settings";
|
||||||
import { classNameFactory } from "@api/Styles";
|
import { classNameFactory } from "@api/Styles";
|
||||||
import ErrorBoundary from "@components/ErrorBoundary";
|
|
||||||
import { Devs } from "@utils/constants";
|
import { Devs } from "@utils/constants";
|
||||||
|
import { Logger } from "@utils/Logger";
|
||||||
import definePlugin, { OptionType } from "@utils/types";
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
import { findByPropsLazy } from "@webpack";
|
import { waitFor } from "@webpack";
|
||||||
import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common";
|
import { ComponentDispatch, FocusLock, i18n, Menu, useEffect, useRef } from "@webpack/common";
|
||||||
import type { HTMLAttributes, ReactElement } from "react";
|
import type { HTMLAttributes, ReactElement } from "react";
|
||||||
|
|
||||||
type SettingsEntry = { section: string, label: string; };
|
type SettingsEntry = { section: string, label: string; };
|
||||||
|
|
||||||
const cl = classNameFactory("");
|
const cl = classNameFactory("");
|
||||||
const Classes = findByPropsLazy("animating", "baseLayer", "bg", "layer", "layers");
|
let Classes: Record<string, string>;
|
||||||
|
waitFor(["animating", "baseLayer", "bg", "layer", "layers"], m => Classes = m);
|
||||||
|
|
||||||
const settings = definePluginSettings({
|
const settings = definePluginSettings({
|
||||||
disableFade: {
|
disableFade: {
|
||||||
|
@ -124,12 +125,19 @@ export default definePlugin({
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
// This is the very outer layer of the entire ui, so we can't wrap this in an ErrorBoundary
|
||||||
|
// without possibly also catching unrelated errors of children.
|
||||||
|
//
|
||||||
|
// Thus, we sanity check webpack modules & do this really hacky try catch to hopefully prevent hard crashes if something goes wrong.
|
||||||
|
// try catch will only catch errors in the Layer function (hence why it's called as a plain function rather than a component), but
|
||||||
|
// not in children
|
||||||
Layer(props: LayerProps) {
|
Layer(props: LayerProps) {
|
||||||
return (
|
if (!FocusLock || !ComponentDispatch || !Classes) {
|
||||||
<ErrorBoundary fallback={() => props.children as any}>
|
new Logger("BetterSettings").error("Failed to find some components");
|
||||||
<Layer {...props} />
|
return props.children;
|
||||||
</ErrorBoundary>
|
}
|
||||||
);
|
|
||||||
|
return <Layer {...props} />;
|
||||||
},
|
},
|
||||||
|
|
||||||
wrapMenu(list: SettingsEntry[]) {
|
wrapMenu(list: SettingsEntry[]) {
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default definePlugin({
|
||||||
|
|
||||||
shouldAttemptRecover = false;
|
shouldAttemptRecover = false;
|
||||||
// This is enough to avoid a crash loop
|
// This is enough to avoid a crash loop
|
||||||
setTimeout(() => shouldAttemptRecover = true, 500);
|
setTimeout(() => shouldAttemptRecover = true, 1000);
|
||||||
} catch { }
|
} catch { }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
8
src/plugins/showTimeoutDuration/README.md
Normal file
8
src/plugins/showTimeoutDuration/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# ShowTimeoutDuration
|
||||||
|
|
||||||
|
Displays how much longer a user's timeout will last.
|
||||||
|
Either in the timeout icon tooltip, or next to it, configurable via settings!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
106
src/plugins/showTimeoutDuration/index.tsx
Normal file
106
src/plugins/showTimeoutDuration/index.tsx
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* Vencord, a Discord client mod
|
||||||
|
* Copyright (c) 2024 Vendicated and contributors
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
import "./styles.css";
|
||||||
|
|
||||||
|
import { definePluginSettings } from "@api/Settings";
|
||||||
|
import ErrorBoundary from "@components/ErrorBoundary";
|
||||||
|
import { Devs } from "@utils/constants";
|
||||||
|
import { Margins } from "@utils/margins";
|
||||||
|
import definePlugin, { OptionType } from "@utils/types";
|
||||||
|
import { findComponentLazy } from "@webpack";
|
||||||
|
import { ChannelStore, Forms, GuildMemberStore, i18n, Text, Tooltip } from "@webpack/common";
|
||||||
|
import { Message } from "discord-types/general";
|
||||||
|
|
||||||
|
const CountDown = findComponentLazy(m => m.prototype?.render?.toString().includes(".MAX_AGE_NEVER"));
|
||||||
|
|
||||||
|
const enum DisplayStyle {
|
||||||
|
Tooltip = "tooltip",
|
||||||
|
Inline = "ssalggnikool"
|
||||||
|
}
|
||||||
|
|
||||||
|
const settings = definePluginSettings({
|
||||||
|
displayStyle: {
|
||||||
|
description: "How to display the timeout duration",
|
||||||
|
type: OptionType.SELECT,
|
||||||
|
restartNeeded: true,
|
||||||
|
options: [
|
||||||
|
{ label: "In the Tooltip", value: DisplayStyle.Tooltip },
|
||||||
|
{ label: "Next to the timeout icon", value: DisplayStyle.Inline, default: true },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderTimeout(message: Message, inline: boolean) {
|
||||||
|
const guildId = ChannelStore.getChannel(message.channel_id)?.guild_id;
|
||||||
|
if (!guildId) return null;
|
||||||
|
|
||||||
|
const member = GuildMemberStore.getMember(guildId, message.author.id);
|
||||||
|
if (!member?.communicationDisabledUntil) return null;
|
||||||
|
|
||||||
|
const countdown = () => (
|
||||||
|
<CountDown
|
||||||
|
deadline={new Date(member.communicationDisabledUntil!)}
|
||||||
|
showUnits
|
||||||
|
stopAtOneSec
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return inline
|
||||||
|
? countdown()
|
||||||
|
: i18n.Messages.GUILD_ENABLE_COMMUNICATION_TIME_REMAINING.format({
|
||||||
|
username: message.author.username,
|
||||||
|
countdown
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default definePlugin({
|
||||||
|
name: "ShowTimeoutDuration",
|
||||||
|
description: "Shows how much longer a user's timeout will last, either in the timeout icon tooltip or next to it",
|
||||||
|
authors: [Devs.Ven],
|
||||||
|
|
||||||
|
settings,
|
||||||
|
|
||||||
|
patches: [
|
||||||
|
{
|
||||||
|
find: ".GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY",
|
||||||
|
replacement: [
|
||||||
|
{
|
||||||
|
match: /(\i)\.Tooltip,{(text:.{0,30}\.Messages\.GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY)/,
|
||||||
|
get replace() {
|
||||||
|
if (settings.store.displayStyle === DisplayStyle.Inline)
|
||||||
|
return "$self.TooltipWrapper,{vcProps:arguments[0],$2";
|
||||||
|
|
||||||
|
return "$1.Tooltip,{text:$self.renderTimeoutDuration(arguments[0])";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
renderTimeoutDuration: ErrorBoundary.wrap(({ message }: { message: Message; }) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Forms.FormText>{i18n.Messages.GUILD_COMMUNICATION_DISABLED_ICON_TOOLTIP_BODY}</Forms.FormText>
|
||||||
|
<Forms.FormText className={Margins.top8}>
|
||||||
|
{renderTimeout(message, false)}
|
||||||
|
</Forms.FormText>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}, { noop: true }),
|
||||||
|
|
||||||
|
TooltipWrapper: ErrorBoundary.wrap(({ vcProps: { message }, ...tooltipProps }: { vcProps: { message: Message; }; }) => {
|
||||||
|
return (
|
||||||
|
<div className="vc-std-wrapper">
|
||||||
|
<Tooltip {...tooltipProps as any} />
|
||||||
|
|
||||||
|
<Text variant="text-md/normal" color="status-danger">
|
||||||
|
{renderTimeout(message, true)} timeout remaining
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}, { noop: true })
|
||||||
|
});
|
4
src/plugins/showTimeoutDuration/styles.css
Normal file
4
src/plugins/showTimeoutDuration/styles.css
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.vc-std-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
|
@ -28,9 +28,12 @@ export default definePlugin({
|
||||||
<a
|
<a
|
||||||
className="vc-voice-download"
|
className="vc-voice-download"
|
||||||
href={src}
|
href={src}
|
||||||
download="voice-message.ogg"
|
|
||||||
onClick={e => e.stopPropagation()}
|
onClick={e => e.stopPropagation()}
|
||||||
aria-label="Download voice message"
|
aria-label="Download voice message"
|
||||||
|
{...IS_DISCORD_DESKTOP
|
||||||
|
? { target: "_blank" } // open externally
|
||||||
|
: { download: "voice-message.ogg" } // download directly (not supported on discord desktop)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<this.Icon />
|
<this.Icon />
|
||||||
</a>
|
</a>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue