mirror of
https://github.com/Equicord/Equicord.git
synced 2025-06-16 18:07:02 -04:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
f4193076fa
14 changed files with 89 additions and 70 deletions
|
@ -18,7 +18,7 @@
|
|||
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { Margins } from "@utils/margins";
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { LazyComponent, LazyComponentWrapper } from "@utils/react";
|
||||
import { React } from "@webpack/common";
|
||||
|
||||
import { ErrorCard } from "./ErrorCard";
|
||||
|
@ -107,9 +107,9 @@ const ErrorBoundary = LazyComponent(() => {
|
|||
}
|
||||
};
|
||||
}) as
|
||||
React.ComponentType<React.PropsWithChildren<Props>> & {
|
||||
LazyComponentWrapper<React.ComponentType<React.PropsWithChildren<Props>> & {
|
||||
wrap<T extends object = any>(Component: React.ComponentType<T>, errorBoundaryProps?: Omit<Props<T>, "wrappedProps">): React.FunctionComponent<T>;
|
||||
};
|
||||
}>;
|
||||
|
||||
ErrorBoundary.wrap = (Component, errorBoundaryProps) => props => (
|
||||
<ErrorBoundary {...errorBoundaryProps} wrappedProps={props}>
|
||||
|
|
|
@ -92,7 +92,7 @@ async function runReporter() {
|
|||
result = Webpack[method](...args);
|
||||
}
|
||||
|
||||
if (result == null || (result.$$vencordInternal != null && result.$$vencordInternal() == null)) throw new Error("Webpack Find Fail");
|
||||
if (result == null || (result.$$vencordGetWrappedComponent != null && result.$$vencordGetWrappedComponent() == null)) throw new Error("Webpack Find Fail");
|
||||
} catch (e) {
|
||||
let logMessage = searchType;
|
||||
if (method === "find" || method === "proxyLazyWebpack" || method === "LazyComponentWebpack") {
|
||||
|
|
|
@ -104,8 +104,8 @@ if (!IS_VANILLA) {
|
|||
super(options);
|
||||
|
||||
if (settings.disableMinSize) {
|
||||
// Disable the Electron call entirely so that Discord can't override it
|
||||
this.setMinimumSize = () => { };
|
||||
// Disable the Electron call entirely so that Discord can't dynamically change the size
|
||||
this.setMinimumSize = (width: number, height: number) => { };
|
||||
}
|
||||
|
||||
initIpc(this);
|
||||
|
|
|
@ -77,7 +77,7 @@ export default definePlugin({
|
|||
replace: "$self.useAccountPanelRef();$&"
|
||||
},
|
||||
{
|
||||
match: /(\.AVATAR,children:.+?renderPopout:\((\i),\i\)=>){(.+?)}(?=,position)(?<=currentUser:(\i).+?)/,
|
||||
match: /(\.AVATAR,children:.+?renderPopout:(\(\i,\i\))=>){(.+?)}(?=,position)(?<=currentUser:(\i).+?)/,
|
||||
replace: (_, rest, popoutProps, originalPopout, currentUser) => `${rest}$self.UserProfile({popoutProps:${popoutProps},currentUser:${currentUser},originalRenderPopout:()=>{${originalPopout}}})`
|
||||
},
|
||||
{
|
||||
|
|
|
@ -36,7 +36,7 @@ export default definePlugin({
|
|||
settings,
|
||||
patches: [
|
||||
{
|
||||
find: "#{intl::BAN_REASON_OPTION_SPAM_ACCOUNT}",
|
||||
find: "#{intl::jeKpoq::raw}", // BAN_CONFIRM_TITLE
|
||||
replacement: {
|
||||
match: /src:\i\("?\d+"?\)/g,
|
||||
replace: "src:$self.source"
|
||||
|
|
|
@ -145,8 +145,7 @@ export default definePlugin({
|
|||
// Thus, we sanity check webpack modules
|
||||
Layer(props: LayerProps) {
|
||||
try {
|
||||
// @ts-ignore
|
||||
[FocusLock.$$vencordInternal(), ComponentDispatch, Classes].forEach(e => e.test);
|
||||
[FocusLock.$$vencordGetWrappedComponent(), ComponentDispatch, Classes].forEach(e => e.test);
|
||||
} catch {
|
||||
new Logger("BetterSettings").error("Failed to find some components");
|
||||
return props.children;
|
||||
|
|
|
@ -20,6 +20,7 @@ import { Devs } from "@utils/constants";
|
|||
import { getCurrentChannel, getCurrentGuild } from "@utils/discord";
|
||||
import { runtimeHashMessageKey } from "@utils/intlHash";
|
||||
import { SYM_LAZY_CACHED, SYM_LAZY_GET } from "@utils/lazy";
|
||||
import { sleep } from "@utils/misc";
|
||||
import { ModalAPI } from "@utils/modal";
|
||||
import { relaunch } from "@utils/native";
|
||||
import { canonicalizeMatch, canonicalizeReplace, canonicalizeReplacement } from "@utils/patches";
|
||||
|
@ -173,8 +174,8 @@ function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
|
|||
function unwrapProxy(value: any) {
|
||||
if (value[SYM_LAZY_GET]) {
|
||||
forceLoad ? currentVal[SYM_LAZY_GET]() : currentVal[SYM_LAZY_CACHED];
|
||||
} else if (value.$$vencordInternal) {
|
||||
return forceLoad ? value.$$vencordInternal() : value;
|
||||
} else if (value.$$vencordGetWrappedComponent) {
|
||||
return forceLoad ? value.$$vencordGetWrappedComponent() : value;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
@ -206,10 +207,13 @@ function loadAndCacheShortcut(key: string, val: any, forceLoad: boolean) {
|
|||
return value;
|
||||
}
|
||||
|
||||
const webpackModulesProbablyLoaded = Webpack.onceReady.then(() => sleep(1000));
|
||||
|
||||
export default definePlugin({
|
||||
name: "ConsoleShortcuts",
|
||||
description: "Adds shorter Aliases for many things on the window. Run `shortcutList` for a list.",
|
||||
authors: [Devs.Ven],
|
||||
startAt: StartAt.Init,
|
||||
|
||||
patches: [
|
||||
{
|
||||
|
@ -221,7 +225,7 @@ export default definePlugin({
|
|||
}
|
||||
],
|
||||
|
||||
startAt: StartAt.Init,
|
||||
|
||||
start() {
|
||||
const shortcuts = makeShortcuts();
|
||||
window.shortcutList = {};
|
||||
|
@ -242,18 +246,16 @@ export default definePlugin({
|
|||
}
|
||||
|
||||
// unproxy loaded modules
|
||||
Webpack.onceReady.then(() => {
|
||||
setTimeout(() => this.eagerLoad(false), 1000);
|
||||
this.eagerLoad(false);
|
||||
|
||||
if (!IS_WEB) {
|
||||
const Native = VencordNative.pluginHelpers.ConsoleShortcuts as PluginNative<typeof import("./native")>;
|
||||
Native.initDevtoolsOpenEagerLoad();
|
||||
}
|
||||
});
|
||||
if (!IS_WEB) {
|
||||
const Native = VencordNative.pluginHelpers.ConsoleShortcuts as PluginNative<typeof import("./native")>;
|
||||
Native.initDevtoolsOpenEagerLoad();
|
||||
}
|
||||
},
|
||||
|
||||
async eagerLoad(forceLoad: boolean) {
|
||||
await Webpack.onceReady;
|
||||
await webpackModulesProbablyLoaded;
|
||||
|
||||
const shortcuts = makeShortcuts();
|
||||
|
||||
|
|
|
@ -85,8 +85,8 @@ export default definePlugin({
|
|||
find: ".USER_MENTION)",
|
||||
replacement: [
|
||||
{
|
||||
match: /(?<=onContextMenu:\i,color:)\i(?=\},)(?<=user:(\i),channel:(\i).+?)/,
|
||||
replace: "$self.getColorInt($1?.id,$2?.id)",
|
||||
match: /(?<=onContextMenu:\i,color:)\i(?<=\.getNickname\((\i),\i,(\i).+?)/,
|
||||
replace: "$self.getColorInt($2?.id,$1)",
|
||||
}
|
||||
],
|
||||
predicate: () => settings.store.chatMentions
|
||||
|
|
|
@ -28,6 +28,7 @@ import { openImageModal } from "@utils/discord";
|
|||
import { classes, copyWithToast } from "@utils/misc";
|
||||
import { ContextMenuApi, FluxDispatcher, Forms, Menu, React, useEffect, useState, useStateFromStores } from "@webpack/common";
|
||||
|
||||
import { SeekBar } from "./SeekBar";
|
||||
import { SpotifyStore, Track } from "./SpotifyStore";
|
||||
|
||||
const cl = classNameFactory("vc-spotify-");
|
||||
|
@ -160,7 +161,7 @@ const seek = debounce((v: number) => {
|
|||
SpotifyStore.seek(v);
|
||||
});
|
||||
|
||||
function SeekBar() {
|
||||
function SpotifySeekBar() {
|
||||
const { duration } = SpotifyStore.track!;
|
||||
|
||||
const [storePosition, isSettingPosition, isPlaying] = useStateFromStores(
|
||||
|
@ -181,6 +182,12 @@ function SeekBar() {
|
|||
}
|
||||
}, [storePosition, isSettingPosition, isPlaying]);
|
||||
|
||||
const onChange = (v: number) => {
|
||||
if (isSettingPosition) return;
|
||||
setPosition(v);
|
||||
seek(v);
|
||||
};
|
||||
|
||||
return (
|
||||
<div id={cl("progress-bar")}>
|
||||
<Forms.FormText
|
||||
|
@ -190,17 +197,13 @@ function SeekBar() {
|
|||
>
|
||||
{msToHuman(position)}
|
||||
</Forms.FormText>
|
||||
<Menu.MenuSliderControl
|
||||
key={position}
|
||||
<SeekBar
|
||||
initialValue={position}
|
||||
minValue={0}
|
||||
maxValue={duration}
|
||||
value={position}
|
||||
onChange={(v: number) => {
|
||||
if (isSettingPosition) return;
|
||||
setPosition(v);
|
||||
seek(v);
|
||||
}}
|
||||
renderValue={msToHuman}
|
||||
onValueChange={onChange}
|
||||
asValueChanges={onChange}
|
||||
onValueRender={msToHuman}
|
||||
/>
|
||||
<Forms.FormText
|
||||
variant="text-xs/medium"
|
||||
|
@ -383,7 +386,7 @@ export function Player() {
|
|||
return (
|
||||
<div id={cl("player")} style={exportTrackImageStyle}>
|
||||
<Info track={track} />
|
||||
<SeekBar />
|
||||
<SpotifySeekBar />
|
||||
<Controls />
|
||||
</div>
|
||||
);
|
||||
|
|
25
src/plugins/spotifyControls/SeekBar.ts
Normal file
25
src/plugins/spotifyControls/SeekBar.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Vencord, a Discord client mod
|
||||
* Copyright (c) 2025 Vendicated and contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { LazyComponent } from "@utils/lazyReact";
|
||||
import { Slider } from "@webpack/common";
|
||||
|
||||
export const SeekBar = LazyComponent(() => {
|
||||
const SliderClass = Slider.$$vencordGetWrappedComponent();
|
||||
|
||||
// Discord's Slider does not update `state.value` when `props.initialValue` changes if state.value is not nullish.
|
||||
// We extend their class and override their `getDerivedStateFromProps` to update the value
|
||||
return class SeekBar extends SliderClass {
|
||||
static getDerivedStateFromProps(props: any, state: any) {
|
||||
const newState = super.getDerivedStateFromProps!(props, state);
|
||||
if (newState) {
|
||||
newState.value = props.initialValue;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
};
|
||||
});
|
|
@ -29,11 +29,8 @@ export const cl = classNameFactory("vc-trans-");
|
|||
const Native = VencordNative.pluginHelpers.Translate as PluginNative<typeof import("./native")>;
|
||||
|
||||
interface GoogleData {
|
||||
src: string;
|
||||
sentences: {
|
||||
// 🏳️⚧️
|
||||
trans: string;
|
||||
}[];
|
||||
translation: string;
|
||||
sourceLanguage: string;
|
||||
}
|
||||
|
||||
interface DeeplData {
|
||||
|
@ -77,21 +74,13 @@ export async function translate(kind: "received" | "sent", text: string): Promis
|
|||
}
|
||||
|
||||
async function googleTranslate(text: string, sourceLang: string, targetLang: string): Promise<TranslationValue> {
|
||||
const url = "https://translate.googleapis.com/translate_a/single?" + new URLSearchParams({
|
||||
// see https://stackoverflow.com/a/29537590 for more params
|
||||
// holy shidd nvidia
|
||||
client: "gtx",
|
||||
// source language
|
||||
sl: sourceLang,
|
||||
// target language
|
||||
tl: targetLang,
|
||||
// what to return, t = translation probably
|
||||
dt: "t",
|
||||
// Send json object response instead of weird array
|
||||
dj: "1",
|
||||
source: "input",
|
||||
// query, duh
|
||||
q: text
|
||||
const url = "https://translate-pa.googleapis.com/v1/translate?" + new URLSearchParams({
|
||||
"params.client": "gtx",
|
||||
"dataTypes": "TRANSLATION",
|
||||
"key": "AIzaSyDLEeFI5OtFBwYBIoK_jj5m32rZK5CkCXA", // some google API key
|
||||
"query.sourceLanguage": sourceLang,
|
||||
"query.targetLanguage": targetLang,
|
||||
"query.text": text,
|
||||
});
|
||||
|
||||
const res = await fetch(url);
|
||||
|
@ -101,14 +90,11 @@ async function googleTranslate(text: string, sourceLang: string, targetLang: str
|
|||
+ `\n${res.status} ${res.statusText}`
|
||||
);
|
||||
|
||||
const { src, sentences }: GoogleData = await res.json();
|
||||
const { sourceLanguage, translation }: GoogleData = await res.json();
|
||||
|
||||
return {
|
||||
sourceLanguage: GoogleLanguages[src] ?? src,
|
||||
text: sentences.
|
||||
map(s => s?.trans).
|
||||
filter(Boolean).
|
||||
join("")
|
||||
sourceLanguage: GoogleLanguages[sourceLanguage] ?? sourceLanguage,
|
||||
text: translation
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -4,26 +4,28 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ComponentType } from "react";
|
||||
import type { ComponentType } from "react";
|
||||
|
||||
import { makeLazy } from "./lazy";
|
||||
|
||||
const NoopComponent = () => null;
|
||||
|
||||
export type LazyComponentWrapper<ComponentType> = ComponentType & { $$vencordGetWrappedComponent(): ComponentType; };
|
||||
|
||||
/**
|
||||
* A lazy component. The factory method is called on first render.
|
||||
* @param factory Function returning a Component
|
||||
* @param attempts How many times to try to get the component before giving up
|
||||
* @returns Result of factory function
|
||||
*/
|
||||
export function LazyComponent<T extends object = any>(factory: () => React.ComponentType<T>, attempts = 5) {
|
||||
export function LazyComponent<T extends object = any>(factory: () => ComponentType<T>, attempts = 5): LazyComponentWrapper<ComponentType<T>> {
|
||||
const get = makeLazy(factory, attempts);
|
||||
const LazyComponent = (props: T) => {
|
||||
const Component = get() ?? NoopComponent;
|
||||
return <Component {...props} />;
|
||||
};
|
||||
|
||||
LazyComponent.$$vencordInternal = get;
|
||||
LazyComponent.$$vencordGetWrappedComponent = get;
|
||||
|
||||
return LazyComponent as ComponentType<T>;
|
||||
return LazyComponent;
|
||||
}
|
||||
|
|
|
@ -16,17 +16,19 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { LazyComponent } from "@utils/react";
|
||||
import { FilterFn, filters, lazyWebpackSearchHistory, waitFor } from "@webpack";
|
||||
import { LazyComponent, LazyComponentWrapper } from "@utils/react";
|
||||
|
||||
export function waitForComponent<T extends React.ComponentType<any> = React.ComponentType<any> & Record<string, any>>(name: string, filter: FilterFn | string | string[]): T {
|
||||
// eslint-disable-next-line path-alias/no-relative
|
||||
import { FilterFn, filters, lazyWebpackSearchHistory, waitFor } from "../webpack";
|
||||
|
||||
export function waitForComponent<T extends React.ComponentType<any> = React.ComponentType<any> & Record<string, any>>(name: string, filter: FilterFn | string | string[]) {
|
||||
if (IS_REPORTER) lazyWebpackSearchHistory.push(["waitForComponent", Array.isArray(filter) ? filter : [filter]]);
|
||||
|
||||
let myValue: T = function () {
|
||||
throw new Error(`Vencord could not find the ${name} Component`);
|
||||
} as any;
|
||||
|
||||
const lazyComponent = LazyComponent(() => myValue) as T;
|
||||
const lazyComponent = LazyComponent(() => myValue) as LazyComponentWrapper<T>;
|
||||
waitFor(filter, (v: any) => {
|
||||
myValue = v;
|
||||
Object.assign(lazyComponent, v);
|
||||
|
|
4
src/webpack/common/types/components.d.ts
vendored
4
src/webpack/common/types/components.d.ts
vendored
|
@ -16,7 +16,7 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import type { ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, ReactNode, Ref } from "react";
|
||||
import type { ComponentClass, ComponentPropsWithRef, ComponentType, CSSProperties, FunctionComponent, HtmlHTMLAttributes, HTMLProps, JSX, KeyboardEvent, MouseEvent, PointerEvent, PropsWithChildren, ReactNode, Ref } from "react";
|
||||
|
||||
|
||||
export type TextVariant = "heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/bold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/bold" | "eyebrow" | "heading-deprecated-14/normal" | "heading-deprecated-14/medium" | "heading-deprecated-14/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "display-sm" | "display-md" | "display-lg" | "code";
|
||||
|
@ -356,7 +356,7 @@ export type SearchableSelect = ComponentType<PropsWithChildren<{
|
|||
"aria-labelledby"?: boolean;
|
||||
}>>;
|
||||
|
||||
export type Slider = ComponentType<PropsWithChildren<{
|
||||
export type Slider = ComponentClass<PropsWithChildren<{
|
||||
initialValue: number;
|
||||
defaultValue?: number;
|
||||
keyboardStep?: number;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue