Merge branch 'dev' into main

This commit is contained in:
byeoon 2024-04-22 13:03:05 -04:00 committed by GitHub
commit 65787848c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 94 additions and 55 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "vencord", "name": "vencord",
"private": "true", "private": "true",
"version": "1.7.7", "version": "1.7.8",
"description": "The cutest Discord client mod", "description": "The cutest Discord client mod",
"homepage": "https://github.com/Vendicated/Vencord#readme", "homepage": "https://github.com/Vendicated/Vencord#readme",
"bugs": { "bugs": {

View file

@ -27,6 +27,7 @@ export { PlainSettings, Settings };
import "./utils/quickCss"; import "./utils/quickCss";
import "./webpack/patchWebpack"; import "./webpack/patchWebpack";
import { openUpdaterModal } from "@components/VencordSettings/UpdaterTab";
import { StartAt } from "@utils/types"; import { StartAt } from "@utils/types";
import { get as dsGet } from "./api/DataStore"; import { get as dsGet } from "./api/DataStore";
@ -85,7 +86,7 @@ async function init() {
syncSettings(); syncSettings();
if (!IS_WEB) { if (!IS_WEB && !IS_UPDATER_DISABLED) {
try { try {
const isOutdated = await checkForUpdates(); const isOutdated = await checkForUpdates();
if (!isOutdated) return; if (!isOutdated) return;
@ -103,16 +104,13 @@ async function init() {
return; return;
} }
if (Settings.notifyAboutUpdates) setTimeout(() => showNotification({
setTimeout(() => showNotification({ title: "A Vencord update is available!",
title: "A Vencord update is available!", body: "Click here to view the update",
body: "Click here to view the update", permanent: true,
permanent: true, noPersist: true,
noPersist: true, onClick: openUpdaterModal!
onClick() { }), 10_000);
SettingsRouter.open("VencordUpdater");
}
}), 10_000);
} catch (err) { } catch (err) {
UpdateLogger.error("Failed to check for updates", err); UpdateLogger.error("Failed to check for updates", err);
} }

View file

@ -29,7 +29,6 @@ import plugins from "~plugins";
const logger = new Logger("Settings"); const logger = new Logger("Settings");
export interface Settings { export interface Settings {
notifyAboutUpdates: boolean;
autoUpdate: boolean; autoUpdate: boolean;
autoUpdateNotification: boolean, autoUpdateNotification: boolean,
useQuickCss: boolean; useQuickCss: boolean;
@ -78,8 +77,7 @@ export interface Settings {
} }
const DefaultSettings: Settings = { const DefaultSettings: Settings = {
notifyAboutUpdates: true, autoUpdate: true,
autoUpdate: false,
autoUpdateNotification: true, autoUpdateNotification: true,
useQuickCss: true, useQuickCss: true,
themeLinks: [], themeLinks: [],

View file

@ -22,6 +22,7 @@ import { Flex } from "@components/Flex";
import { Link } from "@components/Link"; import { Link } from "@components/Link";
import { Margins } from "@utils/margins"; import { Margins } from "@utils/margins";
import { classes } from "@utils/misc"; import { classes } from "@utils/misc";
import { ModalCloseButton, ModalContent, ModalProps, ModalRoot, ModalSize, openModal } from "@utils/modal";
import { relaunch } from "@utils/native"; import { relaunch } from "@utils/native";
import { useAwaiter } from "@utils/react"; import { useAwaiter } from "@utils/react";
import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater"; import { changes, checkForUpdates, getRepo, isNewer, update, updateError, UpdateLogger } from "@utils/updater";
@ -29,7 +30,7 @@ import { Alerts, Button, Card, Forms, Parser, React, Switch, Toasts } from "@web
import gitHash from "~git-hash"; import gitHash from "~git-hash";
import { SettingsTab, wrapTab } from "./shared"; import { handleSettingsTabError, SettingsTab, wrapTab } from "./shared";
function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>>, action: () => any) { function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>>, action: () => any) {
return async () => { return async () => {
@ -38,21 +39,24 @@ function withDispatcher(dispatcher: React.Dispatch<React.SetStateAction<boolean>
await action(); await action();
} catch (e: any) { } catch (e: any) {
UpdateLogger.error("Failed to update", e); UpdateLogger.error("Failed to update", e);
let err: string;
if (!e) { if (!e) {
var err = "An unknown error occurred (error is undefined).\nPlease try again."; err = "An unknown error occurred (error is undefined).\nPlease try again.";
} else if (e.code && e.cmd) { } else if (e.code && e.cmd) {
const { code, path, cmd, stderr } = e; const { code, path, cmd, stderr } = e;
if (code === "ENOENT") if (code === "ENOENT")
var err = `Command \`${path}\` not found.\nPlease install it and try again`; err = `Command \`${path}\` not found.\nPlease install it and try again`;
else { else {
var err = `An error occurred while running \`${cmd}\`:\n`; err = `An error occurred while running \`${cmd}\`:\n`;
err += stderr || `Code \`${code}\`. See the console for more info`; err += stderr || `Code \`${code}\`. See the console for more info`;
} }
} else { } else {
var err = "An unknown error occurred. See the console for more info."; err = "An unknown error occurred. See the console for more info.";
} }
Alerts.show({ Alerts.show({
title: "Oops!", title: "Oops!",
body: ( body: (
@ -186,7 +190,7 @@ function Newer(props: CommonProps) {
} }
function Updater() { function Updater() {
const settings = useSettings(["notifyAboutUpdates", "autoUpdate", "autoUpdateNotification"]); const settings = useSettings(["autoUpdate", "autoUpdateNotification"]);
const [repo, err, repoPending] = useAwaiter(getRepo, { fallbackValue: "Loading..." }); const [repo, err, repoPending] = useAwaiter(getRepo, { fallbackValue: "Loading..." });
@ -203,14 +207,6 @@ function Updater() {
return ( return (
<SettingsTab title="Vencord Updater"> <SettingsTab title="Vencord Updater">
<Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle> <Forms.FormTitle tag="h5">Updater Settings</Forms.FormTitle>
<Switch
value={settings.notifyAboutUpdates}
onChange={(v: boolean) => settings.notifyAboutUpdates = v}
note="Shows a notification on startup"
disabled={settings.autoUpdate}
>
Get notified about new updates
</Switch>
<Switch <Switch
value={settings.autoUpdate} value={settings.autoUpdate}
onChange={(v: boolean) => settings.autoUpdate = v} onChange={(v: boolean) => settings.autoUpdate = v}
@ -253,3 +249,20 @@ function Updater() {
} }
export default IS_UPDATER_DISABLED ? null : wrapTab(Updater, "Updater"); export default IS_UPDATER_DISABLED ? null : wrapTab(Updater, "Updater");
export const openUpdaterModal = IS_UPDATER_DISABLED ? null : function () {
const UpdaterTab = wrapTab(Updater, "Updater");
try {
openModal(wrapTab((modalProps: ModalProps) => (
<ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
<ModalContent className="vc-updater-modal">
<ModalCloseButton onClick={modalProps.onClose} className="vc-updater-modal-close-button" />
<UpdaterTab />
</ModalContent>
</ModalRoot>
), "UpdaterModal"));
} catch {
handleSettingsTabError();
}
};

View file

@ -65,3 +65,11 @@
/* discord also sets cursor: default which prevents the cursor from showing as text */ /* discord also sets cursor: default which prevents the cursor from showing as text */
cursor: initial; cursor: initial;
} }
.vc-updater-modal {
padding: 1.5em !important;
}
.vc-updater-modal-close-button {
float: right;
}

View file

@ -42,11 +42,11 @@ export function SettingsTab({ title, children }: PropsWithChildren<{ title: stri
); );
} }
const onError = onlyOnce(handleComponentFailed); export const handleSettingsTabError = onlyOnce(handleComponentFailed);
export function wrapTab(component: ComponentType, tab: string) { export function wrapTab(component: ComponentType<any>, tab: string) {
return ErrorBoundary.wrap(component, { return ErrorBoundary.wrap(component, {
message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`, message: `Failed to render the ${tab} tab. If this issue persists, try using the installer to reinstall!`,
onError, onError: handleSettingsTabError,
}); });
} }

View file

@ -45,14 +45,14 @@ export default definePlugin({
replacement: { replacement: {
get match() { get match() {
switch (Settings.plugins.Settings.settingsLocation) { switch (Settings.plugins.Settings.settingsLocation) {
case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS\}/; case "top": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.USER_SETTINGS/;
case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS\}/; case "aboveNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.BILLING_SETTINGS/;
case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS\}/; case "belowNitro": return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.APP_SETTINGS/;
case "belowActivity": return /(?<=\{section:(\i\.\i)\.DIVIDER},)\{section:"changelog"/; case "belowActivity": return /(?<=\{section:(\i\.\i)\.DIVIDER},)\{section:"changelog"/;
case "bottom": return /\{section:(\i\.\i)\.CUSTOM,\s*element:.+?}/; case "bottom": return /\{section:(\i\.\i)\.CUSTOM,\s*element:.+?}/;
case "aboveActivity": case "aboveActivity":
default: default:
return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.ACTIVITY_SETTINGS\}/; return /\{section:(\i\.\i)\.HEADER,\s*label:(\i)\.\i\.Messages\.ACTIVITY_SETTINGS/;
} }
}, },
replace: "...$self.makeSettingsCategories($1),$&" replace: "...$self.makeSettingsCategories($1),$&"

View file

@ -22,9 +22,10 @@ import { Devs } from "@utils/constants";
import { isTruthy } from "@utils/guards"; import { isTruthy } from "@utils/guards";
import { useAwaiter } from "@utils/react"; import { useAwaiter } from "@utils/react";
import definePlugin, { OptionType } from "@utils/types"; import definePlugin, { OptionType } from "@utils/types";
import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { findByCodeLazy, findByPropsLazy, findComponentByCodeLazy } from "@webpack";
import { ApplicationAssetUtils, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common"; import { ApplicationAssetUtils, FluxDispatcher, Forms, GuildStore, React, SelectedChannelStore, SelectedGuildStore, UserStore } from "@webpack/common";
const useProfileThemeStyle = findByCodeLazy("profileThemeStyle:", "--profile-gradient-primary-color");
const ActivityComponent = findComponentByCodeLazy("onOpenGameProfile"); const ActivityComponent = findComponentByCodeLazy("onOpenGameProfile");
const ActivityClassName = findByPropsLazy("activity", "buttonColor"); const ActivityClassName = findByPropsLazy("activity", "buttonColor");
@ -392,6 +393,8 @@ export default definePlugin({
settingsAboutComponent: () => { settingsAboutComponent: () => {
const activity = useAwaiter(createActivity); const activity = useAwaiter(createActivity);
const { profileThemeStyle } = useProfileThemeStyle({});
return ( return (
<> <>
<Forms.FormText> <Forms.FormText>
@ -405,7 +408,7 @@ export default definePlugin({
If you want to use image link, download your image and reupload the image to <Link href="https://imgur.com">Imgur</Link> and get the image link by right-clicking the image and select "Copy image address". If you want to use image link, download your image and reupload the image to <Link href="https://imgur.com">Imgur</Link> and get the image link by right-clicking the image and select "Copy image address".
</Forms.FormText> </Forms.FormText>
<Forms.FormDivider /> <Forms.FormDivider />
<div style={{ width: "284px" }}> <div style={{ width: "284px", ...profileThemeStyle }}>
{activity[0] && <ActivityComponent activity={activity[0]} className={ActivityClassName.activity} channelId={SelectedChannelStore.getChannelId()} {activity[0] && <ActivityComponent activity={activity[0]} className={ActivityClassName.activity} channelId={SelectedChannelStore.getChannelId()}
guild={GuildStore.getGuild(SelectedGuildStore.getLastSelectedGuildId())} guild={GuildStore.getGuild(SelectedGuildStore.getLastSelectedGuildId())}
application={{ id: settings.store.appID }} application={{ id: settings.store.appID }}

View file

@ -7,12 +7,22 @@
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import { getCurrentChannel } from "@utils/discord"; import { getCurrentChannel } from "@utils/discord";
import { makeLazy } from "@utils/lazy";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack"; import { filters, find, findByPropsLazy, handleModuleNotFound } from "@webpack";
import { React, RelationshipStore } from "@webpack/common"; import { React, RelationshipStore } from "@webpack/common";
const { Heading, Text } = findByPropsLazy("Heading", "Text"); const { Heading, Text } = findByPropsLazy("Heading", "Text");
const container = findByPropsLazy("memberSinceContainer"); // Workaround for module differing on stable & canary
// FIXME: remove once merged into stable
const getMemberSinceContainer = makeLazy(() => {
for (const name of ["memberSinceWrapper", "memberSinceContainer"]) {
const mod = find(filters.byProps(name), { isIndirect: true });
if (mod) return mod[name];
}
handleModuleNotFound("findByProps", "memberSinceWrapper/memberSinceContainer");
return "";
});
const { getCreatedAtDate } = findByPropsLazy("getCreatedAtDate"); const { getCreatedAtDate } = findByPropsLazy("getCreatedAtDate");
const clydeMoreInfo = findByPropsLazy("clydeMoreInfo"); const clydeMoreInfo = findByPropsLazy("clydeMoreInfo");
const locale = findByPropsLazy("getLocale"); const locale = findByPropsLazy("getLocale");
@ -49,7 +59,7 @@ export default definePlugin({
Friends Since Friends Since
</Heading> </Heading>
<div className={container.memberSinceContainer}> <div className={getMemberSinceContainer()}>
{!!getCurrentChannel()?.guild_id && ( {!!getCurrentChannel()?.guild_id && (
<svg <svg
aria-hidden="true" aria-hidden="true"

View file

@ -50,7 +50,7 @@ export default definePlugin({
patches: [ patches: [
// Chat Mentions // Chat Mentions
{ {
find: "CLYDE_AI_MENTION_COLOR:null,", find: 'location:"UserMention',
replacement: [ replacement: [
{ {
match: /user:(\i),channel:(\i).{0,400}?"@"\.concat\(.+?\)/, match: /user:(\i),channel:(\i).{0,400}?"@"\.concat\(.+?\)/,

View file

@ -35,7 +35,7 @@ const Section = findComponentByCodeLazy(".lastSection", "children:");
const ThemeStore = findStoreLazy("ThemeStore"); const ThemeStore = findStoreLazy("ThemeStore");
const platformHooks: { useLegacyPlatformType(platform: string): string; } = findByPropsLazy("useLegacyPlatformType"); const platformHooks: { useLegacyPlatformType(platform: string): string; } = findByPropsLazy("useLegacyPlatformType");
const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl"); const platforms: { get(type: string): ConnectionPlatform; } = findByPropsLazy("isSupported", "getByUrl");
const getTheme: (user: User, displayProfile: any) => any = findByCodeLazy('--profile-gradient-primary-color":'); const getProfileThemeProps = findByCodeLazy(".getPreviewThemeColors", "primaryColor:");
const enum Spacing { const enum Spacing {
COMPACT, COMPACT,
@ -74,8 +74,8 @@ interface ConnectionPlatform {
icon: { lightSVG: string, darkSVG: string; }; icon: { lightSVG: string, darkSVG: string; };
} }
const profilePopoutComponent = ErrorBoundary.wrap(({ user, displayProfile }: { user: User, displayProfile; }) => const profilePopoutComponent = ErrorBoundary.wrap((props: { user: User, displayProfile; }) =>
<ConnectionsComponent id={user.id} theme={getTheme(user, displayProfile).profileTheme} /> <ConnectionsComponent id={props.user.id} theme={getProfileThemeProps(props).theme} />
); );
const profilePanelComponent = ErrorBoundary.wrap(({ id }: { id: string; }) => const profilePanelComponent = ErrorBoundary.wrap(({ id }: { id: string; }) =>

View file

@ -111,19 +111,28 @@ function MentionWrapper({ data, UserMention, RoleMention, parse, props }: Mentio
export default definePlugin({ export default definePlugin({
name: "ValidUser", name: "ValidUser",
description: "Fix mentions for unknown users showing up as '<@343383572805058560>' (hover over a mention to fix it)", description: "Fix mentions for unknown users showing up as '@unknown-user' (hover over a mention to fix it)",
authors: [Devs.Ven], authors: [Devs.Ven],
tags: ["MentionCacheFix"], tags: ["MentionCacheFix"],
patches: [{ patches: [
find: 'className:"mention"', {
replacement: { find: 'className:"mention"',
// mention = { react: function (data, parse, props) { if (data.userId == null) return RoleMention() else return UserMention() replacement: {
match: /react(?=\(\i,\i,\i\).{0,50}return null==\i\?\(0,\i\.jsx\)\((\i\.\i),.+?jsx\)\((\i\.\i),\{className:"mention")/, // mention = { react: function (data, parse, props) { if (data.userId == null) return RoleMention() else return UserMention()
// react: (...args) => OurWrapper(RoleMention, UserMention, ...args), originalReact: theirFunc match: /react(?=\(\i,\i,\i\).{0,50}return null==.{0,70}\?\(0,\i\.jsx\)\((\i\.\i),.+?jsx\)\((\i\.\i),\{className:"mention")/,
replace: "react:(...args)=>$self.renderMention($1,$2,...args),originalReact" // react: (...args) => OurWrapper(RoleMention, UserMention, ...args), originalReact: theirFunc
replace: "react:(...args)=>$self.renderMention($1,$2,...args),originalReact"
}
},
{
find: "unknownUserMentionPlaceholder:",
replacement: {
match: /unknownUserMentionPlaceholder:/,
replace: "$&false&&"
}
} }
}], ],
renderMention(RoleMention, UserMention, data, parse, props) { renderMention(RoleMention, UserMention, data, parse, props) {
return ( return (

View file

@ -92,7 +92,7 @@ if (IS_DEV && IS_DISCORD_DESKTOP) {
}, 0); }, 0);
} }
function handleModuleNotFound(method: string, ...filter: unknown[]) { export function handleModuleNotFound(method: string, ...filter: unknown[]) {
const err = new Error(`webpack.${method} found no module`); const err = new Error(`webpack.${method} found no module`);
logger.error(err, "Filter:", filter); logger.error(err, "Filter:", filter);