Merge branch 'dev'

This commit is contained in:
thororen1234 2025-09-13 20:20:07 -04:00
commit be56558aaf
No known key found for this signature in database
12 changed files with 119 additions and 252 deletions

View file

@ -71,6 +71,7 @@ export class Channel extends DiscordRecord {
isGroupDM(): boolean;
isGuildStageVoice(): boolean;
isGuildVoice(): boolean;
isGuildVocal(): boolean;
isListenModeCapable(): boolean;
isManaged(): boolean;
isMultiUserDM(): boolean;

View file

@ -214,7 +214,7 @@ export default function PluginModal({ plugin, onRestartNeeded, onClose, transiti
<Tooltip text="Reset to default settings" shouldShow={!isObjectEmpty(pluginSettings)}>
{({ onMouseEnter, onMouseLeave }) => (
<Button
className="button-danger-background"
className={cl("disable-warning")}
size={Button.Sizes.SMALL}
color={Button.Colors.BRAND}
onClick={handleResetClick}
@ -295,8 +295,17 @@ function resetSettings(plugin: Plugin, warningModalProps?: ModalProps, pluginMod
pluginModalProps?.onClose();
}
export function openWarningModal(plugin: Plugin, pluginModalProps: ModalProps, onRestartNeeded?: (pluginName: string) => void) {
if (Settings.ignoreResetWarning) return resetSettings(plugin, pluginModalProps, pluginModalProps, onRestartNeeded);
export function openWarningModal(plugin?: Plugin | null, pluginModalProps?: ModalProps | null, onRestartNeeded?: (pluginName: string) => void, isPlugin = true, enabledPlugins?: number | null, reset?: any) {
if (Settings.ignoreResetWarning && isPlugin) {
if (plugin && pluginModalProps) return resetSettings(plugin, pluginModalProps, pluginModalProps, onRestartNeeded);
return;
} else if (Settings.ignoreResetWarning && !isPlugin) {
return reset();
}
const text = isPlugin
? `You are about to reset all settings for ${plugin?.name} to their default values.`
: `You are about to disable ${enabledPlugins} plugins!`;
openModal(warningModalProps => (
<ModalRoot
@ -312,12 +321,8 @@ export function openWarningModal(plugin: Plugin, pluginModalProps: ModalProps, o
<ModalContent>
<Forms.FormSection>
<Flex className="vc-warning-info">
<img
src="https://media.tenor.com/hapjxf8y50YAAAAi/stop-sign.gif"
alt="Warning"
/>
<Text className="text-normal">
You are about to reset all settings for <strong>{plugin.name}</strong> to their default values.
{text}
</Text>
<Text className="warning-text">
THIS ACTION IS IRREVERSIBLE!
@ -328,21 +333,21 @@ export function openWarningModal(plugin: Plugin, pluginModalProps: ModalProps, o
</Flex>
</Forms.FormSection>
</ModalContent>
<ModalFooter className="modal-footer">
<Flex className="button-container">
<Button
size={Button.Sizes.SMALL}
color={Button.Colors.PRIMARY}
onClick={warningModalProps.onClose}
look={Button.Looks.LINK}
>
Cancel
</Button>
<ModalFooter className="vc-modal-footer">
<Flex className="vc-button-container">
<Flex className="button-group">
<Button
size={Button.Sizes.SMALL}
color={Button.Colors.PRIMARY}
onClick={warningModalProps.onClose}
look={Button.Looks.FILLED}
>
Cancel
</Button>
{!Settings.ignoreResetWarning && (
<Button
size={Button.Sizes.SMALL}
className="button-danger-background"
className={cl("disable-warning")}
onClick={() => {
Settings.ignoreResetWarning = true;
}}
@ -350,21 +355,20 @@ export function openWarningModal(plugin: Plugin, pluginModalProps: ModalProps, o
Disable Warning Forever
</Button>
)}
<Tooltip text="This action cannot be undone. Are you sure?" shouldShow={true}>
{({ onMouseEnter, onMouseLeave }) => (
<Button
size={Button.Sizes.SMALL}
onClick={() => {
<Button
size={Button.Sizes.SMALL}
onClick={() => {
if (isPlugin) {
if (plugin && pluginModalProps)
resetSettings(plugin, pluginModalProps, pluginModalProps, onRestartNeeded);
}}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
className="button-danger-background-no-margin"
>
Confirm Reset
</Button>
)}
</Tooltip>
} else {
reset();
}
}}
className={cl("confirm-reset")}
>
Confirm Reset
</Button>
</Flex>
</Flex>
</ModalFooter>

View file

@ -19,27 +19,24 @@
import "./styles.css";
import * as DataStore from "@api/DataStore";
import { showNotice } from "@api/Notices";
import { Settings, useSettings } from "@api/Settings";
import { useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import { CogWheel, InfoIcon } from "@components/Icons";
import { openPluginModal, SettingsTab } from "@components/settings";
import { AddonCard } from "@components/settings/AddonCard";
import { SettingsTab } from "@components/settings";
import { debounce } from "@shared/debounce";
import { ChangeList } from "@utils/ChangeList";
import { proxyLazy } from "@utils/lazy";
import { Logger } from "@utils/Logger";
import { Margins } from "@utils/margins";
import { classes, isObjectEmpty } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { classes } from "@utils/misc";
import { useAwaiter, useIntersection } from "@utils/react";
import { Plugin } from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { Alerts, Button, Card, Flex, Forms, lodash, Parser, React, Select, Text, TextInput, Toasts, Tooltip, useMemo } from "@webpack/common";
import { Alerts, Button, Card, Forms, lodash, Parser, React, Select, Text, TextInput, Toasts, Tooltip, useMemo } from "@webpack/common";
import { JSX } from "react";
import Plugins, { ExcludedPlugins, PluginMeta } from "~plugins";
import { PluginCard } from "./PluginCard";
import { openWarningModal } from "./PluginModal";
import { StockPluginsCard, UserPluginsCard } from "./PluginStatCards";
// Avoid circular dependency
@ -62,7 +59,7 @@ function showErrorToast(message: string) {
});
}
function ReloadRequiredCard({ required, enabledPlugins, openDisablePluginsModal, resetCheckAndDo }) {
function ReloadRequiredCard({ required, enabledPlugins, openWarningModal, resetCheckAndDo }) {
return (
<Card className={classes(cl("info-card"), required && "vc-warning-card")}>
{required ? (
@ -85,11 +82,9 @@ function ReloadRequiredCard({ required, enabledPlugins, openDisablePluginsModal,
{enabledPlugins.length > 0 && !required && (
<Button
size={Button.Sizes.SMALL}
className="button-danger-background disable-all-button"
className={"vc-plugins-disable-warning vc-modal-align-reset"}
onClick={() => {
if (Settings.ignoreResetWarning) return resetCheckAndDo();
return openDisablePluginsModal(enabledPlugins, resetCheckAndDo);
return openWarningModal(null, null, null, false, enabledPlugins.length, resetCheckAndDo);
}}
>
Disable All Plugins
@ -99,88 +94,6 @@ function ReloadRequiredCard({ required, enabledPlugins, openDisablePluginsModal,
);
}
interface PluginCardProps extends React.HTMLProps<HTMLDivElement> {
plugin: Plugin;
disabled: boolean;
onRestartNeeded(name: string): void;
isNew?: boolean;
}
export function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
const settings = Settings.plugins[plugin.name];
const isEnabled = () => Vencord.Plugins.isPluginEnabled(plugin.name);
function toggleEnabled() {
const wasEnabled = isEnabled();
// If we're enabling a plugin, make sure all deps are enabled recursively.
if (!wasEnabled) {
const { restartNeeded, failures } = startDependenciesRecursive(plugin);
if (failures.length) {
logger.error(`Failed to start dependencies for ${plugin.name}: ${failures.join(", ")}`);
showNotice("Failed to start dependencies: " + failures.join(", "), "Close", () => null);
return;
} else if (restartNeeded) {
// If any dependencies have patches, don't start the plugin yet.
settings.enabled = true;
onRestartNeeded(plugin.name);
return;
}
}
// if the plugin has patches, dont use stopPlugin/startPlugin. Wait for restart to apply changes.
if (plugin.patches?.length) {
settings.enabled = !wasEnabled;
onRestartNeeded(plugin.name);
return;
}
// If the plugin is enabled, but hasn't been started, then we can just toggle it off.
if (wasEnabled && !plugin.started) {
settings.enabled = !wasEnabled;
return;
}
const result = wasEnabled ? stopPlugin(plugin) : startPlugin(plugin);
if (!result) {
settings.enabled = false;
const msg = `Error while ${wasEnabled ? "stopping" : "starting"} plugin ${plugin.name}`;
logger.error(msg);
showErrorToast(msg);
return;
}
settings.enabled = !wasEnabled;
}
return (
<AddonCard
name={plugin.name}
description={plugin.description}
isNew={isNew}
enabled={isEnabled()}
setEnabled={toggleEnabled}
disabled={disabled}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
infoButton={
<button
role="switch"
onClick={() => openPluginModal(plugin, onRestartNeeded)}
className={classes(ButtonClasses.button, cl("info-button"))}
>
{plugin.options && !isObjectEmpty(plugin.options)
? <CogWheel className={cl("info-icon")} />
: <InfoIcon className={cl("info-icon")} />}
</button>
}
/>
);
}
const enum SearchStatus {
ALL,
ENABLED,
@ -387,81 +300,6 @@ export default function PluginSettings() {
}
}
function openDisablePluginsModal(enabledPlugins: String[], resetCheckAndDo: () => void) {
if (Settings.ignoreResetWarning) return resetCheckAndDo();
openModal(warningModalProps => (
<ModalRoot
{...warningModalProps}
size={ModalSize.SMALL}
className="vc-text-selectable"
transitionState={warningModalProps.transitionState}
>
<ModalHeader separator={false}>
<Text className="text-danger">Dangerous Action</Text>
<ModalCloseButton onClick={warningModalProps.onClose} className="vc-modal-close-button" />
</ModalHeader>
<ModalContent>
<Forms.FormSection>
<Flex className="vc-warning-info">
<img
src="https://media.tenor.com/hapjxf8y50YAAAAi/stop-sign.gif"
alt="Warning"
/>
<Text className="warning-text">
WARNING: You are about to disable <span>{enabledPlugins.length}</span> plugins!
</Text>
<Text className="warning-text">
THIS ACTION IS IRREVERSIBLE!
</Text>
<Text className="text-normal margin-bottom">
Are you absolutely sure you want to proceed? You can always enable them back later.
</Text>
</Flex>
</Forms.FormSection>
</ModalContent>
<ModalFooter className="modal-footer">
<Flex className="button-container">
<Button
size={Button.Sizes.SMALL}
color={Button.Colors.PRIMARY}
onClick={warningModalProps.onClose}
look={Button.Looks.LINK}
>
Cancel
</Button>
<Flex className="button-group">
{!Settings.ignoreResetWarning && (
<Button
size={Button.Sizes.SMALL}
className="button-danger-background"
onClick={() => {
Settings.ignoreResetWarning = true;
}}
>
Disable Warning Forever
</Button>
)}
<Tooltip text="This action cannot be undone. Are you sure?" shouldShow={true}>
{({ onMouseEnter, onMouseLeave }) => (
<Button
size={Button.Sizes.SMALL}
className="button-danger-background-no-margin"
onClick={resetCheckAndDo}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
Disable All
</Button>
)}
</Tooltip>
</Flex>
</Flex>
</ModalFooter>
</ModalRoot>
));
}
// Code directly taken from supportHelper.tsx
const isApiPlugin = (plugin: string) => plugin.endsWith("API") || Plugins[plugin].required;
@ -493,7 +331,7 @@ export default function PluginSettings() {
return (
<SettingsTab title="Plugins">
<ReloadRequiredCard required={changes.hasChanges} enabledPlugins={enabledPlugins} openDisablePluginsModal={openDisablePluginsModal} resetCheckAndDo={resetCheckAndDo} />
<ReloadRequiredCard required={changes.hasChanges} enabledPlugins={enabledPlugins} openWarningModal={openWarningModal} resetCheckAndDo={resetCheckAndDo} />
<div className={cl("stats-container")} style={{
marginTop: "16px",

View file

@ -166,58 +166,52 @@
margin-bottom: 10px;
}
.button-danger-background {
background-color: var(--background-color) !important;
.vc-plugins-disable-warning,
.vc-plugin-modal-disable-warning {
background-color: color-mix(in srgb, var(--button-danger-background) 10%, transparent) !important;
border-style: solid !important;
border-width: .1rem !important;
border-color: var(--button-outline-danger-border) !important;
border-color: color-mix(in srgb, var(--button-danger-background) 80%, transparent) !important;
border-radius: 5px !important;
color: color-mix(in srgb, var(--button-danger-background) 100%, transparent) !important;
}
.button-danger-background.top-margin {
margin-top: 10px;
.vc-plugins-disable-warning:hover,
.vc-plugin-modal-disable-warning:hover {
background-color: color-mix(in srgb, var(--button-danger-background-hover) 40%, transparent) !important;
}
.button-danger-background:hover {
background-color: var(--button-outline-danger-background-hover) !important;
border-style: solid;
border-width: .1rem;
border-color: var(--button-outline-danger-border) !important;
}
.button-danger-background-no-margin {
.vc-plugins-confirm-reset,
.vc-plugin-modal-confirm-reset {
background-color: var(--button-danger-background) !important;
color: var(--header-primary);
}
.button-danger-background-no-margin:hover {
.vc-plugins-confirm-reset:hover,
.vc-plugin-modal-confirm-reset:hover {
background-color: var(--button-danger-background-hover) !important;
filter: saturate(75%);
filter: saturate(80%);
}
.vc-modal-close-button {
margin-left: auto !important;
}
.modal-footer {
.vc-modal-align-reset {
align-self: end;
}
.vc-modal-footer {
display: flex;
flex-direction: column;
width: 100%;
box-sizing: border-box;
}
.modal-footer .button-container {
display: flex !important;
justify-content: space-between;
align-items: center;
width: 100%;
}
.button-group {
display: flex !important;
.vc-modal-footer .vc-button-container {
gap: 10px;
align-items: center;
justify-content: end !important;
justify-content: space-between !important;
}
/* Specific to disable all modal */
@ -232,13 +226,6 @@
text-decoration: underline;
}
.disable-all-button {
color: var(--header-primary);
width: 150px;
margin-left: auto;
margin-right: 4.5px !important;
}
.visual-refresh .button-danger-background {
font-size: 16px;
background-color: rgb(240 71 71 / 10%) !important;
@ -248,7 +235,6 @@
font-weight: 500;
padding: 6px 10px;
text-align: center;
margin-top: 10px;
}
.visual-refresh .button-danger-background:hover {

View file

@ -42,9 +42,9 @@ const settings = definePluginSettings({
ignoreTimeout: {
type: OptionType.SLIDER,
description: "Timeout to click ignore",
markers: [0, 1000, 2000, 2500, 5000, 10000],
markers: [0, 1000, 2500, 5000, 10000],
default: 2500,
stickToMarkers: false,
stickToMarkers: true,
}
});

View file

@ -9,7 +9,7 @@ import "./NewPluginsModal.css";
import { Settings, useSettings } from "@api/Settings";
import { classNameFactory } from "@api/Styles";
import ErrorBoundary from "@components/ErrorBoundary";
import { PluginCard } from "@components/settings/tabs/plugins";
import { PluginCard } from "@components/settings/tabs/plugins/PluginCard";
import { ChangeList } from "@utils/ChangeList";
import { classes, Margins } from "@utils/index";
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";

View file

@ -13,7 +13,7 @@ import { openNewPluginsModal } from "./NewPluginsModal";
export default definePlugin({
name: "NewPluginsManager",
description: "Utility that notifies you when new plugins are added to Vencord",
description: "Utility that notifies you when new plugins are added to Equicord",
authors: [Devs.Sqaaakoi],
enabledByDefault: true,
flux: {

View file

@ -20,16 +20,18 @@ const settings = definePluginSettings(
);
const presendObject: MessageSendListener = (_, msg) => {
const sentences = msg.content.split(/(?<=\w\.)\s/);
const blockedWordsArray: string[] = settings.store.blockedWords.split(", ");
const sentences = msg.content.split(/(?<=[.!?]+['")\]]*)(\s+)/);
msg.content = sentences.map((element, i) => {
if (i % 2 === 1) return element;
msg.content = sentences.map(element => {
if (!blockedWordsArray.some(word => element.toLowerCase().startsWith(word.toLocaleLowerCase()))) {
return element.charAt(0).toUpperCase() + element.slice(1);
} else {
return element;
}
}).join(" ");
}).join("");
};
export default definePlugin({

View file

@ -25,8 +25,8 @@ import { CogWheel } from "@components/Icons";
import { Devs } from "@utils/constants";
import definePlugin, { OptionType } from "@utils/types";
import { Guild } from "@vencord/discord-types";
import { findByCodeLazy, findByPropsLazy, mapMangledModuleLazy } from "@webpack";
import { Menu } from "@webpack/common";
import { findByCodeLazy, findByPropsLazy, findStoreLazy, mapMangledModuleLazy } from "@webpack";
import { ChannelStore, Menu } from "@webpack/common";
const { updateGuildNotificationSettings } = findByPropsLazy("updateGuildNotificationSettings");
const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember(", {
@ -36,6 +36,8 @@ const { toggleShowAllChannels } = mapMangledModuleLazy(".onboardExistingMember("
}
});
const isOptInEnabledForGuild = findByCodeLazy(".COMMUNITY)||", ".isOptInEnabled(");
const CollapsedVoiceChannelStore = findStoreLazy("CollapsedVoiceChannelStore");
const collapsedChannels = findByPropsLazy("toggleCollapseGuild");
const settings = definePluginSettings({
guild: {
@ -82,6 +84,11 @@ const settings = definePluginSettings({
description: "Mute Mobile Push Notifications automatically",
type: OptionType.BOOLEAN,
default: true
},
voiceChannels: {
description: "Hide names in Voice channels automatically",
type: OptionType.BOOLEAN,
default: false
}
});
@ -99,8 +106,22 @@ const makeContextMenuPatch: (shouldAddIcon: boolean) => NavContextMenuPatchCallb
);
};
function applyVoiceNameHidingToGuild(guildId: string) {
if (!settings.store.voiceChannels) return;
try {
ChannelStore.getChannelIds(guildId).filter(channelId => {
const channel = ChannelStore.getChannel(channelId);
return channel.isGuildVocal() && !CollapsedVoiceChannelStore.isCollapsed(channelId);
}).forEach(id => collapsedChannels.update(id));
} catch (error) {
console.warn("[NewGuildSettings] Error applying voice name hiding:", error);
}
}
function applyDefaultSettings(guildId: string | null) {
if (guildId === "@me" || guildId === "null" || guildId == null) return;
updateGuildNotificationSettings(guildId,
{
muted: settings.store.guild,
@ -110,15 +131,21 @@ function applyDefaultSettings(guildId: string | null) {
mute_scheduled_events: settings.store.events,
notify_highlights: settings.store.highlights ? 1 : 0
});
if (settings.store.messages !== 3) {
updateGuildNotificationSettings(guildId,
{
message_notifications: settings.store.messages,
});
}
if (settings.store.showAllChannels && isOptInEnabledForGuild(guildId)) {
toggleShowAllChannels(guildId);
}
if (settings.store.voiceChannels) {
applyVoiceNameHidingToGuild(guildId);
}
}
export default definePlugin({

View file

@ -36,6 +36,12 @@ const settings = definePluginSettings({
description: "User IDs (comma + space) whose pings should NEVER be throttled",
restartNeeded: true,
default: ""
},
alwaysPlaySound: {
type: OptionType.BOOLEAN,
description: "Play message sound even when message sound is disabled",
restartNeeded: true,
default: false
}
});
@ -49,16 +55,19 @@ export default definePlugin({
find: ".getDesktopType()===",
replacement: [
{
match: /(\i\.\i\.getDesktopType\(\)===\i\.\i\.NEVER)\)/,
replace: "$&if(!$self.isPrivateChannelRead(arguments[0]?.message))return;else "
match: /(\i\.\i\.getDesktopType\(\)===\i\.\i\.NEVER)\)(?=.*?(\i\.\i\.playNotificationSound\(.{0,5}\)))/,
replace: "$&if(!$self.isPrivateChannelRead(arguments[0]?.message))return;else if($self.playSound())return $2;else "
},
{
match: /sound:(\i\?\i:void 0,volume:\i,onClick)/,
replace: "sound:!$self.isPrivateChannelRead(arguments[0]?.message)?undefined:$1"
match: /sound:(\i\?(\i):void 0,volume:\i,onClick)/,
replace: "sound:!$self.isPrivateChannelRead(arguments[0]?.message)?undefined:$self.playSound()?$2:$1"
}
]
}
],
playSound() {
return settings.store.alwaysPlaySound;
},
isPrivateChannelRead(message: MessageJSON) {
const ignoreList = settings.store.ignoreUsers.split(", ").filter(Boolean);
if (ignoreList.includes(message.author.id)) return true;