Compare commits

...

8 Commits

Author SHA1 Message Date
V
bea7a1711e Bump to v1.3.4 2023-07-08 03:40:31 +02:00
Lewis Crichton
e52ae62441 feat(cloud): support multiple user accounts (#1382)
Co-authored-by: V <vendicated@riseup.net>
2023-07-08 03:36:59 +02:00
V
7cd1d4c60f translate: Add context menu item; fix MLE compatibility 2023-07-08 03:30:16 +02:00
V
2a318e390e QuickCss: Fix wrongly applying quickcss when editing while disabled 2023-07-08 03:13:32 +02:00
V
7c7723bfb1 Plugin Settings: Use Switches for booleans 2023-07-08 03:04:58 +02:00
dolfies
2db0e71e5b fix(RelationshipNotifier): Ignore user-actioned friend requests (#1390) 2023-07-08 02:37:32 +02:00
Ryan Cao
cde8074f44 feat(ClearURLs): add Threads share link tracking param (#1384) 2023-07-08 02:34:16 +02:00
Nuckyz
8b1630bc99 Fix ShowAllMessageButtons (#1392)
Co-authored-by: V <vendicated@riseup.net>
2023-07-08 02:33:37 +02:00
11 changed files with 87 additions and 33 deletions

View File

@ -1,7 +1,7 @@
{ {
"name": "vencord", "name": "vencord",
"private": "true", "private": "true",
"version": "1.3.3", "version": "1.3.4",
"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

@ -16,8 +16,9 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
import { wordsFromCamel, wordsToTitle } from "@utils/text";
import { PluginOptionBoolean } from "@utils/types"; import { PluginOptionBoolean } from "@utils/types";
import { Forms, React, Select } from "@webpack/common"; import { Forms, React, Switch } from "@webpack/common";
import { ISettingElementProps } from "."; import { ISettingElementProps } from ".";
@ -31,11 +32,6 @@ export function SettingBooleanComponent({ option, pluginSettings, definedSetting
onError(error !== null); onError(error !== null);
}, [error]); }, [error]);
const options = [
{ label: "Enabled", value: true, default: def === true },
{ label: "Disabled", value: false, default: typeof def === "undefined" || def === false },
];
function handleChange(newValue: boolean): void { function handleChange(newValue: boolean): void {
const isValid = option.isValid?.call(definedSettings, newValue) ?? true; const isValid = option.isValid?.call(definedSettings, newValue) ?? true;
if (typeof isValid === "string") setError(isValid); if (typeof isValid === "string") setError(isValid);
@ -49,18 +45,17 @@ export function SettingBooleanComponent({ option, pluginSettings, definedSetting
return ( return (
<Forms.FormSection> <Forms.FormSection>
<Forms.FormTitle>{option.description}</Forms.FormTitle> <Switch
<Select value={state}
isDisabled={option.disabled?.call(definedSettings) ?? false} onChange={handleChange}
options={options} note={option.description}
placeholder={option.placeholder ?? "Select an option"} disabled={option.disabled?.call(definedSettings) ?? false}
maxVisibleItems={5}
closeOnSelect={true}
select={handleChange}
isSelected={v => v === state}
serialize={v => String(v)}
{...option.componentProps} {...option.componentProps}
/> hideBorder
style={{ marginBottom: "0.5em" }}
>
{wordsToTitle(wordsFromCamel(id))}
</Switch>
{error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>} {error && <Forms.FormText style={{ color: "var(--text-danger)" }}>{error}</Forms.FormText>}
</Forms.FormSection> </Forms.FormSection>
); );

View File

@ -135,4 +135,5 @@ export const defaultRules = [
"utm_campaign", "utm_campaign",
"utm_term", "utm_term",
"si@open.spotify.com", "si@open.spotify.com",
"igshid",
]; ];

View File

@ -50,7 +50,7 @@ export async function onRelationshipRemove({ relationship: { type, id } }: Relat
() => openUserProfile(user.id) () => openUserProfile(user.id)
); );
break; break;
case RelationshipType.FRIEND_REQUEST: case RelationshipType.INCOMING_REQUEST:
if (settings.store.friendRequestCancels) if (settings.store.friendRequestCancels)
notify( notify(
`A friend request from ${getUniqueUsername(user)} has been removed.`, `A friend request from ${getUniqueUsername(user)} has been removed.`,

View File

@ -58,5 +58,7 @@ export const enum ChannelType {
export const enum RelationshipType { export const enum RelationshipType {
FRIEND = 1, FRIEND = 1,
FRIEND_REQUEST = 3, BLOCKED = 2,
INCOMING_REQUEST = 3,
OUTGOING_REQUEST = 4,
} }

View File

@ -80,7 +80,10 @@ export async function syncAndRunChecks() {
if (settings.store.friendRequestCancels && oldFriends?.requests?.length) { if (settings.store.friendRequestCancels && oldFriends?.requests?.length) {
for (const id of oldFriends.requests) { for (const id of oldFriends.requests) {
if (friends.requests.includes(id)) continue; if (
friends.requests.includes(id) ||
[RelationshipType.FRIEND, RelationshipType.BLOCKED, RelationshipType.OUTGOING_REQUEST].includes(RelationshipStore.getRelationshipType(id))
) continue;
const user = await UserUtils.fetchUser(id).catch(() => void 0); const user = await UserUtils.fetchUser(id).catch(() => void 0);
if (user) if (user)
@ -164,7 +167,7 @@ export async function syncFriends() {
case RelationshipType.FRIEND: case RelationshipType.FRIEND:
friends.friends.push(id); friends.friends.push(id);
break; break;
case RelationshipType.FRIEND_REQUEST: case RelationshipType.INCOMING_REQUEST:
friends.requests.push(id); friends.requests.push(id);
break; break;
} }

View File

@ -28,8 +28,8 @@ export default definePlugin({
{ {
find: ".Messages.MESSAGE_UTILITIES_A11Y_LABEL", find: ".Messages.MESSAGE_UTILITIES_A11Y_LABEL",
replacement: { replacement: {
// isExpanded: V, (?<=,V = shiftKeyDown && !H...;) // isExpanded: V, (?<=,V = shiftKeyDown && !H...,|;)
match: /isExpanded:(\i),(?<=,\1=\i&&(!.+);.+?)/, match: /isExpanded:(\i),(?<=,\1=\i&&(?=(!.+?)[,;]).+?)/,
replace: "isExpanded:$2," replace: "isExpanded:$2,"
} }
} }

View File

@ -44,6 +44,9 @@ export function TranslationAccessory({ message }: { message: Message; }) {
const [translation, setTranslation] = useState<TranslationValue>(); const [translation, setTranslation] = useState<TranslationValue>();
useEffect(() => { useEffect(() => {
// Ignore MessageLinkEmbeds messages
if ((message as any).vencordEmbeddedBy) return;
TranslationSetters.set(message.id, setTranslation); TranslationSetters.set(message.id, setTranslation);
return () => void TranslationSetters.delete(message.id); return () => void TranslationSetters.delete(message.id);

View File

@ -18,19 +18,39 @@
import "./styles.css"; import "./styles.css";
import { addContextMenuPatch, findGroupChildrenByChildId, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu";
import { addAccessory, removeAccessory } from "@api/MessageAccessories"; import { addAccessory, removeAccessory } from "@api/MessageAccessories";
import { addPreSendListener, removePreSendListener } from "@api/MessageEvents"; import { addPreSendListener, removePreSendListener } from "@api/MessageEvents";
import { addButton, removeButton } from "@api/MessagePopover"; import { addButton, removeButton } from "@api/MessagePopover";
import ErrorBoundary from "@components/ErrorBoundary"; import ErrorBoundary from "@components/ErrorBoundary";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { ChannelStore } from "@webpack/common"; import { ChannelStore, Menu } from "@webpack/common";
import { settings } from "./settings"; import { settings } from "./settings";
import { TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon"; import { TranslateChatBarIcon, TranslateIcon } from "./TranslateIcon";
import { handleTranslate, TranslationAccessory } from "./TranslationAccessory"; import { handleTranslate, TranslationAccessory } from "./TranslationAccessory";
import { translate } from "./utils"; import { translate } from "./utils";
const messageCtxPatch: NavContextMenuPatchCallback = (children, { message }) => () => {
if (!message.content) return;
const group = findGroupChildrenByChildId("copy-text", children);
if (!group) return;
group.splice(group.findIndex(c => c?.props?.id === "copy-text") + 1, 0, (
<Menu.MenuItem
id="vc-trans"
label="Translate"
icon={TranslateIcon}
action={async () => {
const trans = await translate("received", message.content);
handleTranslate(message.id, trans);
}}
/>
));
};
export default definePlugin({ export default definePlugin({
name: "Translate", name: "Translate",
description: "Translate messages with Google Translate", description: "Translate messages with Google Translate",
@ -53,6 +73,8 @@ export default definePlugin({
start() { start() {
addAccessory("vc-translation", props => <TranslationAccessory message={props.message} />); addAccessory("vc-translation", props => <TranslationAccessory message={props.message} />);
addContextMenuPatch("message", messageCtxPatch);
addButton("vc-translate", message => { addButton("vc-translate", message => {
if (!message.content) return null; if (!message.content) return null;
@ -78,6 +100,7 @@ export default definePlugin({
stop() { stop() {
removePreSendListener(this.preSend); removePreSendListener(this.preSend);
removeContextMenuPatch("message", messageCtxPatch);
removeButton("vc-translate"); removeButton("vc-translate");
removeAccessory("vc-translation"); removeAccessory("vc-translation");
}, },

View File

@ -28,15 +28,39 @@ import { openModal } from "./modal";
export const cloudLogger = new Logger("Cloud", "#39b7e0"); export const cloudLogger = new Logger("Cloud", "#39b7e0");
export const getCloudUrl = () => new URL(Settings.cloud.url); export const getCloudUrl = () => new URL(Settings.cloud.url);
const cloudUrlOrigin = () => getCloudUrl().origin;
const getUserId = () => {
const id = UserStore.getCurrentUser()?.id;
if (!id) throw new Error("User not yet logged in");
return id;
};
export async function getAuthorization() { export async function getAuthorization() {
const secrets = await DataStore.get<Record<string, string>>("Vencord_cloudSecret") ?? {}; const secrets = await DataStore.get<Record<string, string>>("Vencord_cloudSecret") ?? {};
return secrets[getCloudUrl().origin];
const origin = cloudUrlOrigin();
// we need to migrate from the old format here
if (secrets[origin]) {
await DataStore.update<Record<string, string>>("Vencord_cloudSecret", secrets => {
secrets ??= {};
// use the current user ID
secrets[`${origin}:${getUserId()}`] = secrets[origin];
delete secrets[origin];
return secrets;
});
// since this doesn't update the original object, we'll early return the existing authorization
return secrets[origin];
}
return secrets[`${origin}:${getUserId()}`];
} }
async function setAuthorization(secret: string) { async function setAuthorization(secret: string) {
await DataStore.update<Record<string, string>>("Vencord_cloudSecret", secrets => { await DataStore.update<Record<string, string>>("Vencord_cloudSecret", secrets => {
secrets ??= {}; secrets ??= {};
secrets[getCloudUrl().origin] = secret; secrets[`${cloudUrlOrigin()}:${getUserId()}`] = secret;
return secrets; return secrets;
}); });
} }
@ -44,7 +68,7 @@ async function setAuthorization(secret: string) {
export async function deauthorizeCloud() { export async function deauthorizeCloud() {
await DataStore.update<Record<string, string>>("Vencord_cloudSecret", secrets => { await DataStore.update<Record<string, string>>("Vencord_cloudSecret", secrets => {
secrets ??= {}; secrets ??= {};
delete secrets[getCloudUrl().origin]; delete secrets[`${cloudUrlOrigin()}:${getUserId()}`];
return secrets; return secrets;
}); });
} }
@ -117,8 +141,7 @@ export async function authorizeCloud() {
} }
export async function getCloudAuth() { export async function getCloudAuth() {
const userId = UserStore.getCurrentUser().id;
const secret = await getAuthorization(); const secret = await getAuthorization();
return window.btoa(`${secret}:${userId}`); return window.btoa(`${secret}:${getUserId()}`);
} }

View File

@ -27,8 +27,12 @@ export async function toggle(isEnabled: boolean) {
if (isEnabled) { if (isEnabled) {
style = document.createElement("style"); style = document.createElement("style");
style.id = "vencord-custom-css"; style.id = "vencord-custom-css";
document.head.appendChild(style); document.documentElement.appendChild(style);
VencordNative.quickCss.addChangeListener(css => style.textContent = css); VencordNative.quickCss.addChangeListener(css => {
style.textContent = css;
// At the time of writing this, changing textContent resets the disabled state
style.disabled = !Settings.useQuickCss;
});
style.textContent = await VencordNative.quickCss.get(); style.textContent = await VencordNative.quickCss.get();
} }
} else } else
@ -39,7 +43,7 @@ async function initThemes() {
if (!themesStyle) { if (!themesStyle) {
themesStyle = document.createElement("style"); themesStyle = document.createElement("style");
themesStyle.id = "vencord-themes"; themesStyle.id = "vencord-themes";
document.head.appendChild(themesStyle); document.documentElement.appendChild(themesStyle);
} }
const { themeLinks } = Settings; const { themeLinks } = Settings;