Merge branch 'dev'
This commit is contained in:
commit
3f60486e7d
38 changed files with 225 additions and 556 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "equicord",
|
||||
"private": "true",
|
||||
"version": "1.13.0",
|
||||
"version": "1.13.1",
|
||||
"description": "The other cutest Discord client mod",
|
||||
"homepage": "https://github.com/Equicord/Equicord#readme",
|
||||
"bugs": {
|
||||
|
|
|
|||
13
packages/discord-types/src/components.d.ts
vendored
13
packages/discord-types/src/components.d.ts
vendored
|
|
@ -162,19 +162,6 @@ export type Button = ComponentType<ButtonProps> & {
|
|||
Link: any;
|
||||
};
|
||||
|
||||
export type Switch = ComponentType<PropsWithChildren<{
|
||||
value: boolean;
|
||||
onChange(value: boolean): void;
|
||||
|
||||
disabled?: boolean;
|
||||
hideBorder?: boolean;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
|
||||
note?: ReactNode;
|
||||
tooltipNote?: ReactNode;
|
||||
}>>;
|
||||
|
||||
export type CheckboxAligns = {
|
||||
CENTER: "center";
|
||||
TOP: "top";
|
||||
|
|
|
|||
5
src/components/FormDivider.css
Normal file
5
src/components/FormDivider.css
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.vc-form-divider {
|
||||
border-top: thin solid var(--border-subtle);
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
}
|
||||
13
src/components/FormDivider.tsx
Normal file
13
src/components/FormDivider.tsx
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./FormDivider.css";
|
||||
|
||||
import { classes } from "@utils/misc";
|
||||
|
||||
export function FormDivider({ className }: { className?: string; }) {
|
||||
return <div className={classes("vc-form-divider", className)} />;
|
||||
}
|
||||
29
src/components/FormSwitch.css
Normal file
29
src/components/FormSwitch.css
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
.vc-form-switch-wrapper {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.vc-form-switch {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
> :last-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.vc-form-switch-disabled {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.vc-form-switch-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.vc-form-switch-border {
|
||||
margin-top: 20px;
|
||||
}
|
||||
46
src/components/FormSwitch.tsx
Normal file
46
src/components/FormSwitch.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./FormSwitch.css";
|
||||
|
||||
import { classes } from "@utils/misc";
|
||||
import { Text } from "@webpack/common";
|
||||
import type { PropsWithChildren, ReactNode } from "react";
|
||||
|
||||
import { FormDivider } from "./FormDivider";
|
||||
import { Switch } from "./Switch";
|
||||
|
||||
export interface FormSwitchProps {
|
||||
title: ReactNode;
|
||||
description?: ReactNode;
|
||||
value: boolean;
|
||||
onChange(value: boolean): void;
|
||||
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
hideBorder?: boolean;
|
||||
}
|
||||
|
||||
export function FormSwitch({ onChange, title, value, description, disabled, className, hideBorder }: FormSwitchProps) {
|
||||
return (
|
||||
<div className="vc-form-switch-wrapper">
|
||||
<div className={classes("vc-form-switch", className, disabled && "vc-form-switch-disabled")}>
|
||||
<div className={"vc-form-switch-text"}>
|
||||
<Text variant="text-md/medium">{title}</Text>
|
||||
{description && <Text variant="text-sm/normal">{description}</Text>}
|
||||
</div>
|
||||
|
||||
<Switch checked={value} onChange={onChange} disabled={disabled} />
|
||||
</div>
|
||||
{!hideBorder && <FormDivider className="vc-form-switch-border" />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/** Compatibility with Discord's old FormSwitch */
|
||||
export function FormSwitchCompat(props: PropsWithChildren<any>) {
|
||||
return <FormSwitch {...props} title={props.children ?? ""} description={props.note} />;
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
.vc-switch-slider {
|
||||
transition: 100ms transform ease-in-out;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,11 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Forms, Switch } from "@webpack/common";
|
||||
import "./styles.css";
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Forms } from "@webpack/common";
|
||||
|
||||
interface Props {
|
||||
label: string;
|
||||
|
|
@ -12,6 +16,8 @@ interface Props {
|
|||
themeSettings: Record<string, string>;
|
||||
}
|
||||
|
||||
const cl = classNameFactory("vc-settings-boolean-");
|
||||
|
||||
export function SettingBooleanComponent({ label, name, themeSettings }: Props) {
|
||||
function handleChange(value: boolean) {
|
||||
const corrected = value ? "1" : "0";
|
||||
|
|
@ -21,15 +27,14 @@ export function SettingBooleanComponent({ label, name, themeSettings }: Props) {
|
|||
|
||||
return (
|
||||
<Forms.FormSection>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title={label}
|
||||
key={name}
|
||||
className={cl("switch")}
|
||||
value={themeSettings[name] === "1"}
|
||||
onChange={handleChange}
|
||||
hideBorder
|
||||
style={{ marginBottom: "0.5em" }}
|
||||
>
|
||||
{label}
|
||||
</Switch>
|
||||
/>
|
||||
</Forms.FormSection>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
3
src/components/ThemeSettings/components/styles.css
Normal file
3
src/components/ThemeSettings/components/styles.css
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.vc-settings-boolean-switch {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ import "./AddonCard.css";
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { AddonBadge } from "@components/settings/PluginBadge";
|
||||
import { Switch } from "@components/settings/Switch";
|
||||
import { Switch } from "@components/Switch";
|
||||
import { Text, useRef } from "@webpack/common";
|
||||
import type { MouseEventHandler, ReactNode } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@
|
|||
import "./AddonCard.css";
|
||||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Switch } from "@components/settings";
|
||||
import { AddonBadge } from "@components/settings/PluginBadge";
|
||||
import { Switch } from "@components/settings/Switch";
|
||||
import { Text, useRef } from "@webpack/common";
|
||||
import type { MouseEventHandler, ReactNode } from "react";
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * from "../Switch";
|
||||
export * from "./AddonCard";
|
||||
export * from "./DonateButton";
|
||||
export * from "./PluginBadge";
|
||||
export * from "./QuickAction";
|
||||
export * from "./SpecialCard";
|
||||
export * from "./Switch";
|
||||
export * from "./tabs";
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { Forms, Parser, Switch, TextInput, useEffect, useState } from "@webpack/common";
|
||||
import { Forms, Parser, TextInput, useEffect, useState } from "@webpack/common";
|
||||
|
||||
const RegexGuide = {
|
||||
"\\i": "Special regex escape sequence that matches identifiers (varnames, classnames, etc.)",
|
||||
|
|
@ -69,15 +70,14 @@ export function ReplacementInput({ replacement, setReplacement, replacementError
|
|||
</div>
|
||||
)}
|
||||
|
||||
<Switch
|
||||
<FormSwitch
|
||||
className={Margins.top16}
|
||||
value={isFunc}
|
||||
onChange={setIsFunc}
|
||||
note="'replacement' will be evaled if this is toggled"
|
||||
title={"Treat as Function"}
|
||||
description="'replacement' will be evaled if this is toggled"
|
||||
hideBorder
|
||||
>
|
||||
Treat as Function
|
||||
</Switch>
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Switch } from "@components/settings/Switch";
|
||||
import { Switch } from "@components/Switch";
|
||||
import { PluginOptionBoolean } from "@utils/types";
|
||||
import { React, useState } from "@webpack/common";
|
||||
|
||||
|
|
|
|||
|
|
@ -19,13 +19,14 @@
|
|||
import { showNotification } from "@api/Notifications";
|
||||
import { Settings, useSettings } from "@api/Settings";
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Grid } from "@components/Grid";
|
||||
import { Link } from "@components/Link";
|
||||
import { SettingsTab, wrapTab } from "@components/settings/tabs/BaseTab";
|
||||
import { authorizeCloud, cloudLogger, deauthorizeCloud, getCloudAuth, getCloudUrl } from "@utils/cloud";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { deleteCloudSettings, getCloudSettings, putCloudSettings } from "@utils/settingsSync";
|
||||
import { Alerts, Button, Forms, Switch, Tooltip, useState } from "@webpack/common";
|
||||
import { Alerts, Button, Forms, Tooltip, useState } from "@webpack/common";
|
||||
|
||||
function validateUrl(url: string) {
|
||||
try {
|
||||
|
|
@ -72,14 +73,13 @@ function SettingsSyncSection() {
|
|||
Synchronize your settings to the cloud. This allows easy synchronization across multiple devices with
|
||||
minimal effort.
|
||||
</Forms.FormText>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
key="cloud-sync"
|
||||
disabled={!cloud.authenticated}
|
||||
title="Settings Sync"
|
||||
value={cloud.settingsSync}
|
||||
onChange={v => { cloud.settingsSync = v; }}
|
||||
>
|
||||
Settings Sync
|
||||
</Switch>
|
||||
disabled={!cloud.authenticated}
|
||||
/>
|
||||
<div className="vc-cloud-settings-sync-grid">
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
|
|
@ -143,8 +143,10 @@ function CloudTab() {
|
|||
<br />
|
||||
You can swap between Equicord and Vencord's different cloud instances below if needed.
|
||||
</Forms.FormText>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
key="backend"
|
||||
title="Enable Cloud Integrations"
|
||||
description="This will request authorization if you have not yet set up cloud integrations."
|
||||
value={settings.cloud.authenticated}
|
||||
onChange={v => {
|
||||
if (v)
|
||||
|
|
@ -152,10 +154,7 @@ function CloudTab() {
|
|||
else
|
||||
settings.cloud.authenticated = v;
|
||||
}}
|
||||
note="This will request authorization if you have not yet set up cloud integrations."
|
||||
>
|
||||
Enable Cloud Integrations
|
||||
</Switch>
|
||||
/>
|
||||
<Forms.FormTitle tag="h5">Backend URL</Forms.FormTitle>
|
||||
<Forms.FormText className={Margins.bottom8}>
|
||||
Which backend to use when using cloud integrations.
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
import { useSettings } from "@api/Settings";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Link } from "@components/Link";
|
||||
import { handleSettingsTabError, SettingsTab, wrapTab } from "@components/settings";
|
||||
import { Margins } from "@utils/margins";
|
||||
|
|
@ -27,7 +28,7 @@ import { ModalCloseButton, ModalContent, ModalProps, ModalRoot, ModalSize, openM
|
|||
import { relaunch } from "@utils/native";
|
||||
import { useAwaiter } from "@utils/react";
|
||||
import { changes, checkForUpdates, getRepo, isNewer, shortGitHash, update, updateError, UpdateLogger } from "@utils/updater";
|
||||
import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@webpack/common";
|
||||
import { Alerts, Button, Card, Forms, Parser, React, Toasts } from "@webpack/common";
|
||||
|
||||
import gitHash from "~git-hash";
|
||||
|
||||
|
|
@ -204,21 +205,19 @@ function Updater() {
|
|||
return (
|
||||
<SettingsTab title="Equicord Updater">
|
||||
<Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Automatically update"
|
||||
description="Automatically update Equicord without confirmation prompt"
|
||||
value={settings.autoUpdate}
|
||||
onChange={(v: boolean) => settings.autoUpdate = v}
|
||||
note="Automatically update Equicord without confirmation prompt"
|
||||
>
|
||||
Automatically update
|
||||
</Switch>
|
||||
<Switch
|
||||
/>
|
||||
<FormSwitch
|
||||
value={settings.autoUpdateNotification}
|
||||
onChange={(v: boolean) => settings.autoUpdateNotification = v}
|
||||
note="Shows a notification when Equicord automatically updates"
|
||||
title="Get notified when an automatic update completes"
|
||||
description="Shows a notification when Equicord automatically updates"
|
||||
disabled={!settings.autoUpdate}
|
||||
>
|
||||
Get notified when an automatic update completes
|
||||
</Switch>
|
||||
/>
|
||||
|
||||
<Forms.FormTitle tag="h5">Repo</Forms.FormTitle>
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
|||
import { useSettings } from "@api/Settings";
|
||||
import { ErrorCard } from "@components/ErrorCard";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { identity } from "@utils/misc";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Button, Forms, Select, Slider, Switch, Text } from "@webpack/common";
|
||||
import { Button, Forms, Select, Slider, Text } from "@webpack/common";
|
||||
|
||||
export function NotificationSection() {
|
||||
return (
|
||||
|
|
@ -89,12 +90,11 @@ function NotificationSettings() {
|
|||
/>
|
||||
|
||||
<Forms.FormTitle tag="h5" className={Margins.top16 + " " + Margins.bottom8}>Missed Notification Count</Forms.FormTitle>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="When refocusing discord a notification will popup with how you missed"
|
||||
value={settings.missed}
|
||||
onChange={(v: boolean) => settings.missed = v}
|
||||
>
|
||||
When refocusing discord a notification will popup with how you missed
|
||||
</Switch>
|
||||
/>
|
||||
|
||||
<Forms.FormTitle tag="h5" className={Margins.top16 + " " + Margins.bottom8}>Notification Timeout</Forms.FormTitle>
|
||||
<Forms.FormText className={Margins.bottom16}>Set to 0s to never automatically time out</Forms.FormText>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import "./VencordTab.css";
|
|||
|
||||
import { openNotificationLogModal } from "@api/Notifications/notificationLog";
|
||||
import { useSettings } from "@api/Settings";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { FolderIcon, GithubIcon, LogIcon, PaintbrushIcon, RestartIcon } from "@components/Icons";
|
||||
import { openContributorModal, openPluginModal, SettingsTab, wrapTab } from "@components/settings";
|
||||
import { DonateButton, InviteButton } from "@components/settings/DonateButton";
|
||||
|
|
@ -18,13 +19,13 @@ import { DONOR_ROLE_ID, GUILD_ID, VC_DONOR_ROLE_ID, VC_GUILD_ID } from "@utils/c
|
|||
import { Margins } from "@utils/margins";
|
||||
import { identity, isAnyPluginDev } from "@utils/misc";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { Button, Flex, Forms, GuildMemberStore, React, Select, Switch, UserStore } from "@webpack/common";
|
||||
import { Button, Flex, Forms, GuildMemberStore, React, Select, UserStore } from "@webpack/common";
|
||||
import BadgeAPI from "plugins/_api/badges";
|
||||
|
||||
import { openNotificationSettingsModal } from "./NotificationSettings";
|
||||
|
||||
const DEFAULT_DONATE_IMAGE = "https://cdn.discordapp.com/emojis/1026533090627174460.png";
|
||||
const SHIGGY_DONATE_IMAGE = "https://i.imgur.com/57ATLZu.png";
|
||||
const SHIGGY_DONATE_IMAGE = "https://equicord.org/assets/favicon.png";
|
||||
|
||||
const VENNIE_DONATOR_IMAGE = "https://cdn.discordapp.com/emojis/1238120638020063377.png";
|
||||
const COZY_CONTRIB_IMAGE = "https://cdn.discordapp.com/emojis/1026533070955872337.png";
|
||||
|
|
@ -210,11 +211,12 @@ function EquicordSettings() {
|
|||
{Switches.map(
|
||||
s =>
|
||||
s && (
|
||||
<Switch
|
||||
<FormSwitch
|
||||
key={s.key}
|
||||
value={settings[s.key]}
|
||||
onChange={v => (settings[s.key] = v)}
|
||||
note={
|
||||
title={s.title}
|
||||
description={
|
||||
s.warning.enabled ? (
|
||||
<>
|
||||
{s.note}
|
||||
|
|
@ -226,9 +228,7 @@ function EquicordSettings() {
|
|||
s.note
|
||||
)
|
||||
}
|
||||
>
|
||||
{s.title}
|
||||
</Switch>
|
||||
/>
|
||||
),
|
||||
)}
|
||||
</Forms.FormSection>
|
||||
|
|
|
|||
|
|
@ -9,11 +9,12 @@ import "./styles.css";
|
|||
import { ChatBarButton } from "@api/ChatButtons";
|
||||
import { DataStore } from "@api/index";
|
||||
import { definePluginSettings, migratePluginSettings, Settings } from "@api/Settings";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { getCurrentChannel, sendMessage } from "@utils/discord";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, Forms, React, Switch, TextInput } from "@webpack/common";
|
||||
import { Button, Forms, React, TextInput } from "@webpack/common";
|
||||
|
||||
type ButtonEntry = {
|
||||
id: string;
|
||||
|
|
@ -181,13 +182,12 @@ function ButtonEntries() {
|
|||
<div className="chatButtonsPlus-header">
|
||||
<Forms.FormTitle tag="h5" className="chatButtonsPlus-title">Button {i + 1}</Forms.FormTitle>
|
||||
<div className="chatButtonsPlus-controls">
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Enabled"
|
||||
value={entry.enabled ?? true}
|
||||
onChange={value => setEnabled(entry.id, value)}
|
||||
className="chatButtonsPlus-toggle"
|
||||
>
|
||||
Enabled
|
||||
</Switch>
|
||||
/>
|
||||
<Button
|
||||
onClick={() => removeButtonEntry(entry.id, update)}
|
||||
look={Button.Looks.OUTLINED}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
import { AudioPlayerInterface, playAudio } from "@api/AudioPlayer";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { useForceUpdater } from "@utils/react";
|
||||
import { makeRange } from "@utils/types";
|
||||
import { findLazy } from "@webpack";
|
||||
import { Button, Card, Forms, React, Select, showToast, Slider, Switch } from "@webpack/common";
|
||||
import { Button, Card, Forms, React, Select, showToast, Slider } from "@webpack/common";
|
||||
import { ComponentType, Ref, SyntheticEvent } from "react";
|
||||
|
||||
import { deleteAudio, getAllAudio, saveAudio, StoredAudioFile } from "./audioStore";
|
||||
|
|
@ -148,7 +149,8 @@ export function SoundOverrideComponent({ type, override, onChange }: {
|
|||
|
||||
return (
|
||||
<Card className={cl("card")}>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title={type.name}
|
||||
value={override.enabled || false}
|
||||
onChange={async val => {
|
||||
console.log(`[CustomSounds] Setting ${type.id} enabled to:`, val);
|
||||
|
|
@ -169,9 +171,7 @@ export function SoundOverrideComponent({ type, override, onChange }: {
|
|||
}}
|
||||
className={Margins.bottom16}
|
||||
hideBorder
|
||||
>
|
||||
{type.name}
|
||||
</Switch>
|
||||
/>
|
||||
|
||||
{override.enabled && (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { DataStore } from "@api/index";
|
|||
import { definePluginSettings } from "@api/Settings";
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { Flex } from "@components/Flex";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { DeleteIcon } from "@components/Icons";
|
||||
import { EquicordDevs } from "@utils/constants";
|
||||
import { Margins } from "@utils/margins";
|
||||
|
|
@ -18,7 +19,7 @@ import { useForceUpdater } from "@utils/react";
|
|||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Message } from "@vencord/discord-types";
|
||||
import { findByCodeLazy, findByPropsLazy } from "@webpack";
|
||||
import { Button, ChannelStore, FluxDispatcher, Forms, Select, SelectedChannelStore, Switch, TabBar, TextInput, Tooltip, UserStore, useState } from "@webpack/common";
|
||||
import { Button, ChannelStore, FluxDispatcher, Forms, Select, SelectedChannelStore, TabBar, TextInput, Tooltip, UserStore, useState } from "@webpack/common";
|
||||
import type { JSX, PropsWithChildren } from "react";
|
||||
|
||||
type IconProps = JSX.IntrinsicElements["svg"];
|
||||
|
|
@ -225,15 +226,14 @@ function KeywordEntries() {
|
|||
<DeleteIcon />
|
||||
</Button>
|
||||
</Flex>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Ignore Case"
|
||||
className={cl("switch")}
|
||||
value={values[i].ignoreCase}
|
||||
onChange={() => {
|
||||
setIgnoreCase(i, !values[i].ignoreCase);
|
||||
}}
|
||||
style={{ marginTop: "0.5em", marginRight: "40px" }}
|
||||
>
|
||||
Ignore Case
|
||||
</Switch>
|
||||
/>
|
||||
<Forms.FormTitle tag="h5">Whitelist/Blacklist</Forms.FormTitle>
|
||||
<Flex flexDirection="row">
|
||||
<div style={{ flexGrow: 1 }}>
|
||||
|
|
|
|||
|
|
@ -14,3 +14,8 @@
|
|||
padding: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vc-keywordnotify-switch {
|
||||
margin-top: 0.5em;
|
||||
margin-right: 40px;
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
export const images = {
|
||||
cross: "https://i.imgur.com/XxRnu3b.png",
|
||||
cross: "https://cdn.discordapp.com/emojis/1423430200938463315.webp",
|
||||
deviceImage: {
|
||||
success:
|
||||
"https://github.com/nexpid/Themelings/raw/data/icons/images/native/img_remote_auth_succeeded.png",
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { OptionType } from "@utils/types";
|
||||
import { Card, Flex, Forms, Switch, TextInput, Tooltip } from "@webpack/common";
|
||||
import { Card, Flex, Forms, TextInput, Tooltip } from "@webpack/common";
|
||||
|
||||
import { Tag, tags } from "./consts";
|
||||
import { TagSettings } from "./types";
|
||||
|
|
@ -68,21 +69,19 @@ function SettingsComponent() {
|
|||
className={Margins.bottom16}
|
||||
/>
|
||||
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Show in messages"
|
||||
value={tagSettings[t.name]?.showInChat ?? true}
|
||||
onChange={v => tagSettings[t.name].showInChat = v}
|
||||
hideBorder
|
||||
>
|
||||
Show in messages
|
||||
</Switch>
|
||||
/>
|
||||
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Show in member list and profiles"
|
||||
value={tagSettings[t.name]?.showInNotChat ?? true}
|
||||
onChange={v => tagSettings[t.name].showInNotChat = v}
|
||||
hideBorder
|
||||
>
|
||||
Show in member list and profiles
|
||||
</Switch>
|
||||
/>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,12 +6,13 @@
|
|||
|
||||
import { findGroupChildrenByChildId } from "@api/ContextMenu";
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { getCurrentChannel } from "@utils/discord";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Message } from "@vencord/discord-types";
|
||||
import { Button, Menu, Select, Switch, Text, UploadHandler, useEffect, useState } from "@webpack/common";
|
||||
import { Button, Menu, Select, Text, UploadHandler, useEffect, useState } from "@webpack/common";
|
||||
|
||||
import { QuoteIcon } from "./components";
|
||||
import { canvasToBlob, fetchImageAsBlob, FixUpQuote, wrapText } from "./utils";
|
||||
|
|
@ -219,7 +220,7 @@ function QuoteModal({ message, ...props }: ModalProps & { message: Message; }) {
|
|||
<img alt="" src="" id="quoterPreview" style={{ borderRadius: "20px", width: "100%" }} />
|
||||
<br /><br />
|
||||
<br /><br />
|
||||
<Switch value={gray} onChange={setGray}>Grayscale</Switch>
|
||||
<FormSwitch title="Grayscale" value={gray} onChange={setGray} />
|
||||
<Select
|
||||
look={1}
|
||||
options={Object.keys(ImageStyle)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { classNameFactory } from "@api/Styles";
|
|||
import { EquicordDevs, IS_MAC } from "@utils/constants";
|
||||
import { closeModal, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Button, ChannelRouter, ChannelStore, IconUtils, React, SelectedChannelStore, Toasts, UserStore } from "@webpack/common";
|
||||
import { Button, ChannelRouter, ChannelStore, IconUtils, React, RelationshipStore, SelectedChannelStore, Toasts, UserStore } from "@webpack/common";
|
||||
|
||||
const STORAGE_KEY = "RDMSwitch_history";
|
||||
const MAX_HISTORY = 50;
|
||||
|
|
@ -203,7 +203,8 @@ function getDisplayForChannel(id: string) {
|
|||
if (ch.isDM()) {
|
||||
const uid = ch.recipients?.[0];
|
||||
const user = uid ? UserStore.getUser(uid) : null;
|
||||
return { name: user?.globalName ?? user?.username ?? "DM", avatar: user ? IconUtils.getUserAvatarURL(user, true, 64) : "" };
|
||||
const friendNick = user ? RelationshipStore.getNickname(user.id) : null;
|
||||
return { name: friendNick ?? user?.globalName ?? user?.username ?? "DM", avatar: user ? IconUtils.getUserAvatarURL(user, true, 64) : "" };
|
||||
}
|
||||
|
||||
if (ch.isGroupDM()) {
|
||||
|
|
|
|||
|
|
@ -5,11 +5,12 @@
|
|||
*/
|
||||
|
||||
import { CheckedTextInput } from "@components/CheckedTextInput";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { identity } from "@utils/misc";
|
||||
import { Activity } from "@vencord/discord-types";
|
||||
import { ActivityFlags, ActivityType } from "@vencord/discord-types/enums";
|
||||
import { Card, Forms, PresenceStore, React, Select, SnowflakeUtils, Switch, TextInput, UserStore } from "@webpack/common";
|
||||
import { Card, Forms, PresenceStore, React, Select, SnowflakeUtils, TextInput, UserStore } from "@webpack/common";
|
||||
|
||||
import { AppIdSetting, makeEmptyAppId } from ".";
|
||||
|
||||
|
|
@ -78,16 +79,15 @@ export function ReplaceSettings({ appIds, update, save }: SettingsProps) {
|
|||
<Card style={{ padding: "1em", opacity: !setting.enabled ? "60%" : "" }} key={i}>
|
||||
{
|
||||
isValidSnowflake(setting.appId) ?
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Apply edits to app"
|
||||
value={setting.enabled}
|
||||
onChange={value => {
|
||||
onChange(value, i, "enabled");
|
||||
}}
|
||||
className={Margins.bottom8}
|
||||
hideBorder={true}
|
||||
>
|
||||
Apply edits to app
|
||||
</Switch> : <Forms.FormTitle tag="h3">Add new application</Forms.FormTitle>
|
||||
/> : <Forms.FormTitle tag="h3">Add new application</Forms.FormTitle>
|
||||
}
|
||||
<Forms.FormTitle className={`${Margins.top8} ${Margins.bottom8}`}>Application ID</Forms.FormTitle>
|
||||
<CheckedTextInput
|
||||
|
|
@ -201,31 +201,26 @@ export function ReplaceSettings({ appIds, update, save }: SettingsProps) {
|
|||
/>
|
||||
</>
|
||||
}
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Hide assets (large & small images)"
|
||||
value={setting.disableAssets}
|
||||
onChange={value => {
|
||||
onChange(value, i, "disableAssets");
|
||||
}}
|
||||
className={Margins.top8}
|
||||
hideBorder={true}
|
||||
style={{ marginBottom: "0" }}
|
||||
>
|
||||
Hide assets (large & small images)
|
||||
</Switch>
|
||||
<Switch
|
||||
/>
|
||||
<FormSwitch
|
||||
title="Hide timestamps"
|
||||
value={setting.disableTimestamps}
|
||||
onChange={value => {
|
||||
onChange(value, i, "disableTimestamps");
|
||||
}}
|
||||
className={Margins.top8}
|
||||
hideBorder={true}
|
||||
style={{ marginBottom: "0" }}
|
||||
>
|
||||
Hide timestamps
|
||||
</Switch>
|
||||
hideBorder={true} />
|
||||
</>
|
||||
}
|
||||
</Card>
|
||||
</Card >
|
||||
)
|
||||
}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@
|
|||
|
||||
.vc-rpceditor-horizontal div:first-child {
|
||||
padding-right: 5px;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,8 +5,9 @@
|
|||
*/
|
||||
|
||||
import { Flex } from "@components/Flex";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
|
||||
import { Button, ChannelStore, Forms, React, SelectedChannelStore, Slider, Switch, Text, TextArea, UploadHandler } from "@webpack/common";
|
||||
import { Button, ChannelStore, Forms, React, SelectedChannelStore, Slider, Text, TextArea, UploadHandler } from "@webpack/common";
|
||||
|
||||
import { characters } from "../characters.json";
|
||||
import Canvas from "./Canvas";
|
||||
|
|
@ -117,7 +118,7 @@ export default function SekaiStickersModal({ modalProps, settings }: { modalProp
|
|||
<Slider minValue={10} asValueChanges={val => setFontSize(Math.round(val))} maxValue={100} initialValue={fontSize} keyboardStep={1} orientation={"horizontal"} onValueRender={(v: number) => String(Math.round(v))} />
|
||||
<Forms.FormTitle>Spacing</Forms.FormTitle>
|
||||
<Slider markers={[18, 36, 72, 100]} stickToMarkers={false} minValue={18} maxValue={100} initialValue={spaceSize} asValueChanges={e => setSpaceSize(e)} onValueRender={e => String(Math.round(e))} />
|
||||
<Switch value={curve} onChange={val => setCurve(val)}>Enable curve</Switch>
|
||||
<FormSwitch title="Enable curve" value={curve} onChange={val => setCurve(val)} />
|
||||
<Button onClick={() => openModal(props => <CharSelectModal modalProps={props} setCharacter={setChracter} />)}>Switch Character</Button>
|
||||
</div>
|
||||
</Flex>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ function CheckBadge({ badge, author }: { badge: string; author: User; }): JSX.El
|
|||
className={roleIconClassName}
|
||||
name="Equicord Contributor"
|
||||
size={20}
|
||||
src={"https://i.imgur.com/57ATLZu.png"}
|
||||
src={"https://equicord.org/assets/favicon.png"}
|
||||
/>
|
||||
</span>
|
||||
) : null;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ export default settings;
|
|||
const BadgeSettings = () => {
|
||||
const [images, setImages] = useState([
|
||||
{ src: "https://cdn.nest.rip/uploads/78cb1e77-b7a6-4242-9089-e91f866159bf.png", shown: settings.store.showEquicordDonor, title: "Equicord donor badges", key: "EquicordDonor", position: settings.store.EquicordDonorPosition },
|
||||
{ src: "https://i.imgur.com/rJDRtUB.png", shown: settings.store.showEquicordContributor, title: "Equicord contributor badge", key: "EquicordContributer", position: settings.store.EquicordContributorPosition },
|
||||
{ src: "https://equicord.org/assets/favicon.png", shown: settings.store.showEquicordContributor, title: "Equicord contributor badge", key: "EquicordContributer", position: settings.store.EquicordContributorPosition },
|
||||
{ src: "https://cdn.discordapp.com/emojis/1026533070955872337.png", shown: settings.store.showVencordDonor, title: "Vencord donor badges", key: "VencordDonor", position: settings.store.VencordDonorPosition },
|
||||
{ src: "https://cdn.discordapp.com/emojis/1092089799109775453.png", shown: settings.store.showVencordContributor, title: "Vencord contributor badge", key: "VencordContributer", position: settings.store.VencordContributorPosition },
|
||||
{ src: "https://cdn.discordapp.com/badge-icons/bf01d1073931f921909045f3a39fd264.png", shown: settings.store.showDiscordProfile, title: "Discord profile badges (HypeSquad, Discord Staff, Active Developer, etc.)", key: "DiscordProfile", position: settings.store.DiscordProfilePosition },
|
||||
|
|
|
|||
|
|
@ -1,421 +0,0 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2023 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { isTruthy } from "@utils/guards";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { Activity, Channel, FluxStore } from "@vencord/discord-types";
|
||||
import { ActivityType } from "@vencord/discord-types/enums";
|
||||
import { findByPropsLazy, findStoreLazy } from "@webpack";
|
||||
import { ApplicationAssetUtils, ChannelStore, FluxDispatcher, GuildStore, IconUtils, PresenceStore, RelationshipStore, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common";
|
||||
|
||||
const presenceStore = findByPropsLazy("getLocalPresence");
|
||||
const GuildMemberCountStore = findStoreLazy("GuildMemberCountStore") as FluxStore & { getMemberCount(guildId: string): number | null; };
|
||||
const ChannelMemberStore = findStoreLazy("ChannelMemberStore") as FluxStore & {
|
||||
getProps(guildId: string, channelId: string): { groups: { count: number; id: string; }[]; };
|
||||
};
|
||||
const VoiceStates = findByPropsLazy("getVoiceStatesForChannel");
|
||||
const chino = "https://i.imgur.com/Dsa2rQy.png";
|
||||
const wysi = "https://i.imgur.com/uKtXde9.gif";
|
||||
|
||||
async function getApplicationAsset(key: string): Promise<string> {
|
||||
if (/https?:\/\/(cdn|media)\.discordapp\.(com|net)\/attachments\//.test(key)) return "mp:" + key.replace(/https?:\/\/(cdn|media)\.discordapp\.(com|net)\//, "");
|
||||
return (await ApplicationAssetUtils.fetchAssetIds(settings.store.appID!, [key]))[0];
|
||||
}
|
||||
|
||||
const enum TimestampMode {
|
||||
NONE,
|
||||
NOW,
|
||||
TIME,
|
||||
CUSTOM,
|
||||
}
|
||||
|
||||
const settings = definePluginSettings({
|
||||
appID: {
|
||||
type: OptionType.STRING,
|
||||
description: "Application ID (required)",
|
||||
onChange: onChange,
|
||||
isValid: (value: string) => {
|
||||
if (!value) return "Application ID is required.";
|
||||
if (value && !/^\d+$/.test(value)) return "Application ID must be a number.";
|
||||
return true;
|
||||
}
|
||||
},
|
||||
userAvatarAsSmallImage: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Use your avatar as small image",
|
||||
onChange: onChange,
|
||||
default: false
|
||||
},
|
||||
exposeDmsUsername: {
|
||||
type: OptionType.BOOLEAN,
|
||||
description: "Expose current DMs username",
|
||||
onChange: onChange,
|
||||
default: false
|
||||
},
|
||||
type: {
|
||||
type: OptionType.SELECT,
|
||||
description: "Activity type",
|
||||
onChange: onChange,
|
||||
options: [
|
||||
{
|
||||
label: "Playing",
|
||||
value: ActivityType.PLAYING,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
label: "Streaming",
|
||||
value: ActivityType.STREAMING
|
||||
},
|
||||
{
|
||||
label: "Listening",
|
||||
value: ActivityType.LISTENING
|
||||
},
|
||||
{
|
||||
label: "Watching",
|
||||
value: ActivityType.WATCHING
|
||||
},
|
||||
{
|
||||
label: "Competing",
|
||||
value: ActivityType.COMPETING
|
||||
}
|
||||
]
|
||||
},
|
||||
streamLink: {
|
||||
type: OptionType.STRING,
|
||||
description: "Twitch.tv or Youtube.com link (only for Streaming activity type)",
|
||||
onChange: onChange,
|
||||
disabled: isStreamLinkDisabled,
|
||||
isValid: isStreamLinkValid
|
||||
},
|
||||
timestampMode: {
|
||||
type: OptionType.SELECT,
|
||||
description: "Timestamp mode",
|
||||
onChange: onChange,
|
||||
options: [
|
||||
{
|
||||
label: "None",
|
||||
value: TimestampMode.NONE,
|
||||
default: true
|
||||
},
|
||||
{
|
||||
label: "Since discord open",
|
||||
value: TimestampMode.NOW
|
||||
},
|
||||
{
|
||||
label: "Same as your current time",
|
||||
value: TimestampMode.TIME
|
||||
},
|
||||
{
|
||||
label: "Custom",
|
||||
value: TimestampMode.CUSTOM
|
||||
}
|
||||
]
|
||||
},
|
||||
startTime: {
|
||||
type: OptionType.NUMBER,
|
||||
description: "Start timestamp (only for custom timestamp mode)",
|
||||
onChange: onChange,
|
||||
disabled: isTimestampDisabled,
|
||||
isValid: (value: number) => {
|
||||
if (value && value < 0) return "Start timestamp must be greater than 0.";
|
||||
return true;
|
||||
}
|
||||
},
|
||||
endTime: {
|
||||
type: OptionType.NUMBER,
|
||||
description: "End timestamp (only for custom timestamp mode)",
|
||||
onChange: onChange,
|
||||
disabled: isTimestampDisabled,
|
||||
isValid: (value: number) => {
|
||||
if (value && value < 0) return "End timestamp must be greater than 0.";
|
||||
return true;
|
||||
}
|
||||
},
|
||||
secretStuff: {
|
||||
type: OptionType.STRING,
|
||||
description: "A list of server/channel ids separated by commas, which are hidden from the RPC.",
|
||||
onChange: onChange,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
|
||||
function onChange() {
|
||||
setRpc(true);
|
||||
setRpc();
|
||||
}
|
||||
|
||||
function isStreamLinkDisabled() {
|
||||
return settings.store.type !== ActivityType.STREAMING;
|
||||
}
|
||||
|
||||
function isStreamLinkValid(value: string) {
|
||||
if (!isStreamLinkDisabled() && !/https?:\/\/(www\.)?(twitch\.tv|youtube\.com)\/\w+/.test(value)) return "Streaming link must be a valid URL.";
|
||||
return true;
|
||||
}
|
||||
|
||||
function isTimestampDisabled() {
|
||||
return settings.store.timestampMode !== TimestampMode.CUSTOM;
|
||||
}
|
||||
|
||||
function onlineFriendCount(): number {
|
||||
let onlineFriends = 0;
|
||||
const relationships = RelationshipStore.getFriendIDs();
|
||||
for (const id of relationships) {
|
||||
if (PresenceStore.getStatus(id) !== "offline") {
|
||||
onlineFriends++;
|
||||
}
|
||||
}
|
||||
return onlineFriends;
|
||||
}
|
||||
|
||||
function totalFriendCount(): number {
|
||||
return RelationshipStore.getFriendCount();
|
||||
}
|
||||
|
||||
function memberCount(): string {
|
||||
const channelId = SelectedChannelStore.getChannelId();
|
||||
const guildId = SelectedGuildStore.getGuildId()!;
|
||||
const { groups } = ChannelMemberStore.getProps(guildId, channelId);
|
||||
const total = GuildMemberCountStore.getMemberCount(guildId);
|
||||
|
||||
if (total == null)
|
||||
return "";
|
||||
|
||||
const online =
|
||||
(groups.length === 1 && groups[0].id === "unknown")
|
||||
? 0
|
||||
: groups.reduce((count, curr) => count + (curr.id === "offline" ? 0 : curr.count), 0);
|
||||
|
||||
return online === 0 ? `${total} members` : `${online} online / ${total} total`;
|
||||
}
|
||||
|
||||
function getChannelIconURL(channel: Channel): string {
|
||||
if (channel.icon) return `https://cdn.discordapp.com/channel-icons/${channel.id}/${channel.icon}.webp?size=128`;
|
||||
return chino;
|
||||
}
|
||||
|
||||
function getSecretStuff(): string[] {
|
||||
return settings.store.secretStuff.split(",").map(id => id.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
async function createActivity(): Promise<Activity | undefined> {
|
||||
|
||||
const {
|
||||
appID,
|
||||
userAvatarAsSmallImage,
|
||||
exposeDmsUsername,
|
||||
streamLink,
|
||||
timestampMode,
|
||||
startTime,
|
||||
endTime,
|
||||
} = settings.store;
|
||||
|
||||
let { type } = settings.store;
|
||||
|
||||
let appName = "Equicord";
|
||||
let details = "";
|
||||
let state = "";
|
||||
let imageBig = "";
|
||||
const imageBigTooltip = undefined;
|
||||
let imageSmall = "";
|
||||
const imageSmallTooltip = undefined;
|
||||
let buttonOneText: string | undefined;
|
||||
let buttonOneURL: string | undefined;
|
||||
let buttonTwoText: string | undefined;
|
||||
let buttonTwoURL: string | undefined;
|
||||
|
||||
|
||||
const channelId = SelectedChannelStore.getChannelId();
|
||||
const guildId = SelectedGuildStore.getGuildId()!;
|
||||
const voiceId = SelectedChannelStore.getVoiceChannelId();
|
||||
const currentUser = UserStore.getCurrentUser();
|
||||
if (userAvatarAsSmallImage) imageSmall = currentUser.getAvatarURL(undefined, undefined, true) || chino;
|
||||
|
||||
const secretStuff = getSecretStuff();
|
||||
const isSecret = secretStuff.includes(channelId) || secretStuff.includes(guildId);
|
||||
|
||||
if (isSecret) {
|
||||
appName = "Hidden Channel/Guild";
|
||||
details = "#secret";
|
||||
state = "hehe";
|
||||
imageBig = chino;
|
||||
} else if (!channelId) {
|
||||
appName = "Friends List";
|
||||
details = `${onlineFriendCount()} online / ${totalFriendCount()} total`;
|
||||
state = `${GuildStore.getGuildCount()} servers`;
|
||||
imageBig = chino;
|
||||
} else {
|
||||
if (channelId === "@home" || channelId === "customize-community" || channelId === "channel-browser" || channelId === "onboarding") {
|
||||
appName = channelId === "@home" ? "Server Guide" : channelId === "customize-community" ? "Channels & Roles" : channelId === "channel-browser" ? "Browse Channels" : "Onboarding";
|
||||
const guild = GuildStore.getGuild(guildId);
|
||||
if (guild) {
|
||||
details = guild.name;
|
||||
state = memberCount();
|
||||
imageBig = IconUtils.getGuildIconURL({ id: guild.id, icon: guild.icon, canAnimate: true, size: 512 }) || chino;
|
||||
if (guild.vanityURLCode) {
|
||||
buttonOneText = `Join ${guild.name.slice(0, 26)}`;
|
||||
buttonOneURL = `https://discord.gg/${guild.vanityURLCode}`;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
const channel = ChannelStore.getChannel(channelId);
|
||||
|
||||
if (channel.isDM()) {
|
||||
const recipient = UserStore.getUser(channel.recipients[0]);
|
||||
appName = exposeDmsUsername ? `${recipient.username}'s DM` : "Direct Messages";
|
||||
details = `${onlineFriendCount()} online / ${totalFriendCount()} total`;
|
||||
state = `${GuildStore.getGuildCount()} servers`;
|
||||
imageBig = recipient.getAvatarURL(undefined, undefined, true) || chino;
|
||||
}
|
||||
|
||||
if (channel.isGroupDM()) {
|
||||
appName = channel.name || "Group DM";
|
||||
details = `${channel.recipients.length + 1} members`;
|
||||
imageBig = getChannelIconURL(channel);
|
||||
}
|
||||
|
||||
const guild = GuildStore.getGuild(guildId);
|
||||
if (guild) {
|
||||
appName = `#${channel.name}`;
|
||||
details = guild.name;
|
||||
state = memberCount();
|
||||
imageBig = IconUtils.getGuildIconURL({ id: guild.id, icon: guild.icon, canAnimate: true, size: 512 }) || chino;
|
||||
if (guild.vanityURLCode) {
|
||||
buttonOneText = `Join ${guild.name.slice(0, 31 - 5)}`;
|
||||
buttonOneURL = `https://discord.gg/${guild.vanityURLCode}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (voiceId) {
|
||||
const voiceChannel = ChannelStore.getChannel(voiceId);
|
||||
const voiceGuild = GuildStore.getGuild(voiceChannel.guild_id);
|
||||
const voiceMemberCount = Object.keys(VoiceStates.getVoiceStatesForChannel(voiceChannel.id)).length;
|
||||
buttonTwoText = `🔊 ${voiceGuild.name.slice(0, 31 - 6 - voiceMemberCount.toString().length)} [${voiceMemberCount}]`;
|
||||
buttonTwoURL = `https://discordapp.com/channels/${voiceGuild.id}/${voiceChannel.id}`;
|
||||
|
||||
if (!buttonOneText) {
|
||||
buttonOneText = buttonTwoText;
|
||||
buttonOneURL = buttonTwoURL;
|
||||
buttonTwoText = undefined;
|
||||
buttonTwoURL = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if ((new Date().getHours() === 7 || new Date().getHours() === 19) && new Date().getMinutes() === 27) {
|
||||
type = ActivityType.PLAYING;
|
||||
appName = "WHEN YOU SEE IT";
|
||||
imageBig = wysi;
|
||||
details = "7:27 👈";
|
||||
state = "";
|
||||
}
|
||||
|
||||
const activity: Activity = {
|
||||
application_id: appID || "0",
|
||||
name: appName,
|
||||
state,
|
||||
details,
|
||||
type,
|
||||
flags: 1 << 0,
|
||||
};
|
||||
|
||||
if (type === ActivityType.STREAMING) activity.url = streamLink;
|
||||
|
||||
switch (timestampMode) {
|
||||
case TimestampMode.NOW:
|
||||
activity.timestamps = {
|
||||
start: Date.now()
|
||||
};
|
||||
break;
|
||||
case TimestampMode.TIME:
|
||||
activity.timestamps = {
|
||||
start: Date.now() - (new Date().getHours() * 3600 + new Date().getMinutes() * 60 + new Date().getSeconds()) * 1000
|
||||
};
|
||||
break;
|
||||
case TimestampMode.CUSTOM:
|
||||
if (startTime || endTime) {
|
||||
activity.timestamps = {};
|
||||
if (startTime) activity.timestamps.start = startTime;
|
||||
if (endTime) activity.timestamps.end = endTime;
|
||||
}
|
||||
break;
|
||||
case TimestampMode.NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (buttonOneText) {
|
||||
activity.buttons = [
|
||||
buttonOneText,
|
||||
buttonTwoText
|
||||
].filter(isTruthy);
|
||||
|
||||
activity.metadata = {
|
||||
button_urls: [
|
||||
buttonOneURL,
|
||||
buttonTwoURL
|
||||
].filter(isTruthy)
|
||||
};
|
||||
}
|
||||
|
||||
if (imageBig) {
|
||||
activity.assets = {
|
||||
large_image: await getApplicationAsset(imageBig),
|
||||
large_text: imageBigTooltip || undefined
|
||||
};
|
||||
}
|
||||
|
||||
if (imageSmall) {
|
||||
activity.assets = {
|
||||
...activity.assets,
|
||||
small_image: await getApplicationAsset(imageSmall),
|
||||
small_text: imageSmallTooltip || undefined
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
for (const k in activity) {
|
||||
if (k === "type") continue;
|
||||
const v = activity[k];
|
||||
if (!v || v.length === 0)
|
||||
delete activity[k];
|
||||
}
|
||||
|
||||
return activity;
|
||||
}
|
||||
|
||||
let timeout: NodeJS.Timeout | null = null;
|
||||
|
||||
async function setRpc(disable?: boolean) {
|
||||
const activities: any = presenceStore.getActivities();
|
||||
const activity: Activity | undefined = !activities.length || (activities.length === 1 && activities[0].application_id === settings.store.appID) ? await createActivity() : undefined;
|
||||
|
||||
FluxDispatcher.dispatch({
|
||||
type: "LOCAL_ACTIVITY_UPDATE",
|
||||
activity: !disable ? activity : null,
|
||||
socketId: "CustomRPC",
|
||||
});
|
||||
|
||||
if (!disable) {
|
||||
timeout = setTimeout(() => setRpc(), 4000);
|
||||
} else if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
}
|
||||
|
||||
export default definePlugin({
|
||||
name: "VencordRPC",
|
||||
description: "how to expose yourself",
|
||||
authors: [Devs.AutumnVN],
|
||||
start: setRpc,
|
||||
stop: () => setRpc(true),
|
||||
settings
|
||||
});
|
||||
|
|
@ -5,12 +5,13 @@
|
|||
*/
|
||||
|
||||
import { definePluginSettings } from "@api/Settings";
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Devs } from "@utils/constants";
|
||||
import { makeLazy } from "@utils/lazy";
|
||||
import { closeModal, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalProps, ModalRoot, openModal } from "@utils/modal";
|
||||
import definePlugin, { OptionType } from "@utils/types";
|
||||
import { findByProps, wreq } from "@webpack";
|
||||
import { Button, Flex, Forms, Switch, Text, Timestamp, useState } from "@webpack/common";
|
||||
import { Button, Flex, Forms, Text, Timestamp, useState } from "@webpack/common";
|
||||
|
||||
import TarFile from "./tar";
|
||||
import * as Webpack from "./webpack";
|
||||
|
|
@ -136,13 +137,12 @@ function TarModal({ modalProps, close }: { modalProps: ModalProps; close(): void
|
|||
</Flex>
|
||||
</div>
|
||||
|
||||
<Switch
|
||||
<FormSwitch
|
||||
value={patched}
|
||||
onChange={v => settings.store.patched = v}
|
||||
title={settings.def.patched.description}
|
||||
hideBorder
|
||||
>
|
||||
{settings.def.patched.description}
|
||||
</Switch>
|
||||
/>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import { ContextMenuApi, Menu, Toasts, UserStore } from "@webpack/common";
|
|||
import { EquicordDonorModal, VencordDonorModal } from "./modals";
|
||||
|
||||
const CONTRIBUTOR_BADGE = "https://cdn.discordapp.com/emojis/1092089799109775453.png?size=64";
|
||||
const EQUICORD_CONTRIBUTOR_BADGE = "https://i.imgur.com/57ATLZu.png";
|
||||
const EQUICORD_CONTRIBUTOR_BADGE = "https://equicord.org/assets/favicon.png";
|
||||
const EQUICORD_DONOR_BADGE = "https://cdn.nest.rip/uploads/78cb1e77-b7a6-4242-9089-e91f866159bf.png";
|
||||
|
||||
const ContributorBadge: ProfileBadge = {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { insertTextIntoChatInputBox } from "@utils/discord";
|
||||
import {
|
||||
ModalContent,
|
||||
|
|
@ -25,7 +26,7 @@ import {
|
|||
ModalRoot,
|
||||
openModal,
|
||||
} from "@utils/modal";
|
||||
import { Button, Forms, React, Switch, TextInput } from "@webpack/common";
|
||||
import { Button, Forms, React, TextInput } from "@webpack/common";
|
||||
|
||||
import { encrypt } from "../index";
|
||||
|
||||
|
|
@ -65,14 +66,13 @@ function EncModal(props: ModalProps) {
|
|||
setPassword(e);
|
||||
}}
|
||||
/>
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Don't use a Cover"
|
||||
value={noCover}
|
||||
onChange={(e: boolean) => {
|
||||
setNoCover(e);
|
||||
}}
|
||||
>
|
||||
Don't use a Cover
|
||||
</Switch>
|
||||
/>
|
||||
</ModalContent>
|
||||
|
||||
<ModalFooter>
|
||||
|
|
|
|||
|
|
@ -16,9 +16,10 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FormSwitch } from "@components/FormSwitch";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { ModalCloseButton, ModalContent, ModalHeader, ModalProps, ModalRoot } from "@utils/modal";
|
||||
import { Forms, SearchableSelect, Switch, useMemo } from "@webpack/common";
|
||||
import { Forms, SearchableSelect, useMemo } from "@webpack/common";
|
||||
|
||||
import { settings } from "./settings";
|
||||
import { cl, getLanguages } from "./utils";
|
||||
|
|
@ -60,14 +61,13 @@ function AutoTranslateToggle() {
|
|||
const value = settings.use(["autoTranslate"]).autoTranslate;
|
||||
|
||||
return (
|
||||
<Switch
|
||||
<FormSwitch
|
||||
title="Auto Translate"
|
||||
description={settings.def.autoTranslate.description}
|
||||
value={value}
|
||||
onChange={v => settings.store.autoTranslate = v}
|
||||
note={settings.def.autoTranslate.description}
|
||||
hideBorder
|
||||
>
|
||||
Auto Translate
|
||||
</Switch>
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { FormSwitchCompat } from "@components/FormSwitch";
|
||||
import { LazyComponent } from "@utils/lazyReact";
|
||||
import * as t from "@vencord/discord-types";
|
||||
import { filters, mapMangledModuleLazy, waitFor } from "@webpack";
|
||||
|
|
@ -37,7 +38,8 @@ export const Forms = {
|
|||
|
||||
export const Card = waitForComponent<t.Card>("Card", filters.componentByCode(".editable),", ".outline:"));
|
||||
export const Button = waitForComponent<t.Button>("Button", filters.componentByCode("#{intl::A11Y_LOADING_STARTED}))),!1"));
|
||||
export const Switch = waitForComponent<t.Switch>("Switch", filters.componentByCode(".labelRow,ref:", ".disabledText"));
|
||||
/** @deprecated Use FormSwitch from Vencord */
|
||||
export const Switch = FormSwitchCompat as never;
|
||||
export const Checkbox = waitForComponent<t.Checkbox>("Checkbox", filters.componentByCode(".checkboxWrapperDisabled:"));
|
||||
|
||||
const Tooltips = mapMangledModuleLazy(".tooltipTop,bottom:", {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue