Compare commits

...

22 commits

Author SHA1 Message Date
sadan4
f9b0cfe708
Merge a88db90860 into c7e5295da0 2024-09-18 21:34:12 +02:00
Vendicated
c7e5295da0
SearchReply => FullSearchContext ~ now adds all options back
Some checks are pending
Sync to Codeberg / codeberg (push) Waiting to run
test / test (push) Waiting to run
2024-09-18 21:33:46 +02:00
sadan4
a88db90860
Merge branch 'dev' into emoteCloner 2024-09-15 21:44:54 -04:00
sadan4
74b03c0962
Discard changes to src/utils/constants.ts 2024-09-15 21:43:14 -04:00
sadan
7d70d53083
remove hang status and add channel statuses 2024-09-15 21:42:52 -04:00
sadan4
b3bf32abd7
Merge branch 'dev' into emoteCloner 2024-09-04 20:20:42 -04:00
sadan
f8bf23db1f
fix contsatns 2024-09-02 01:16:32 -04:00
sadan4
6ac7edccec
Merge branch 'dev' into emoteCloner 2024-09-02 01:11:50 -04:00
sadan4
6366cc2e12
Merge branch 'main' into emoteCloner 2024-09-02 01:11:25 -04:00
sadan4
8bba7b7ab7
Merge branch 'main' into emoteCloner 2024-07-30 23:13:11 -04:00
sadan4
efc38a1d2e
Merge branch 'main' into emoteCloner 2024-07-20 18:20:05 -04:00
sadan
b4e4085382
fix patch modifying the user object 2024-07-15 13:18:26 -04:00
sadan4
85e3fa4cc5
Merge branch 'main' into emoteCloner 2024-07-14 23:18:50 -04:00
sadan
359d7564a5
fix wacky logic 2024-07-14 23:16:58 -04:00
sadan4
04bfbe4553
Merge branch 'main' into emoteCloner 2024-07-14 22:13:21 -04:00
sadan
bdae37ff23
fix var names, regex, and types 2024-07-11 02:20:07 -04:00
sadan4
8e649cfcc4
Update src/plugins/emoteCloner/index.tsx
Co-authored-by: Drew <84212701+MrDiamondDog@users.noreply.github.com>
2024-07-11 02:09:21 -04:00
sadan
9c819e83b3
fix regex remove fake nitro name part 2024-07-10 23:35:19 -04:00
sadan
850b940306
fix regex and remove log 2024-07-10 22:35:27 -04:00
sadan
add443e67b
inline patch 2024-07-10 22:33:36 -04:00
sadan
eed1c2b400
Merge branch 'main' into emoteCloner 2024-07-10 13:57:54 -04:00
sadan
d7366ae171
read desc
add emote cloner to
- emojis in user statuses
- hang statuses (vc statuses)
add name finding for fake nitro emojis that have &name=emoji_name
2024-07-10 02:28:18 -04:00
5 changed files with 142 additions and 87 deletions

View file

@ -25,11 +25,16 @@ import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/moda
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { findByCodeLazy, findStoreLazy } from "@webpack"; import { findByCodeLazy, findStoreLazy } from "@webpack";
import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common";
import { Channel } from "discord-types/general";
import { Promisable } from "type-fest"; import { Promisable } from "type-fest";
const StickersStore = findStoreLazy("StickersStore"); const StickersStore = findStoreLazy("StickersStore");
const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START"); const uploadEmoji = findByCodeLazy(".GUILD_EMOJIS(", "EMOJI_UPLOAD_START");
const ChannelStatusStore: {
getChannelStatus(c: Channel): string;
} = findStoreLazy("ChannelStatusStore");
interface Sticker { interface Sticker {
t: "Sticker"; t: "Sticker";
description: string; description: string;
@ -272,12 +277,12 @@ function CloneModal({ data }: { data: Sticker | Emoji; }) {
); );
} }
function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Omit<Sticker | Emoji, "t">>) { function buildMenuItem(type: "Emoji" | "Sticker", fetchData: () => Promisable<Omit<Sticker | Emoji, "t">>, label?: string) {
return ( return (
<Menu.MenuItem <Menu.MenuItem
id="emote-cloner" id={`emote-cloner${label ?? ""}`}
key="emote-cloner" key="emote-cloner"
label={`Clone ${type}`} label={label ?? `Clone ${type}`}
action={() => action={() =>
openModalLazy(async () => { openModalLazy(async () => {
const res = await fetchData(); const res = await fetchData();
@ -360,13 +365,57 @@ const expressionPickerPatch: NavContextMenuPatchCallback = (children, props: { t
} }
}; };
const emojiRegex = /https:\/\/cdn\.discordapp\.com\/emojis\/(\d+)\.([a-zA-Z]{3,4}).*/;
const imageContextPatch: NavContextMenuPatchCallback = (children, props: {
src: string;
}) => {
// this context menu is called on normal images, as well as stock emojis.
const matches = [...props.src.match(emojiRegex) ?? []];
if (matches.length === 0) return;
children.push(buildMenuItem("Emoji", () => ({
id: matches[1],
isAnimated: (matches[2] === "gif"),
name: "ProfileEmoji"
})));
};
const emojiMatchRegex = /<(a?):(\w+):(\d{19})>/g;
const channelContextStatusPatch: NavContextMenuPatchCallback = (children, props: {
channel: Channel;
}) => {
const status = ChannelStatusStore.getChannelStatus(props.channel);
if (!status) return;
const emojis = [...status.matchAll(emojiMatchRegex)];
if (emojis.length === 0) return;
console.log(emojis);
children.push((
<Menu.MenuItem id="vc-emoteCloner-item" label="Clone Emoji">
{
emojis.map(([_, animated, name, id]) => (
buildMenuItem("Emoji", () => ({
id,
name,
isAnimated: !!animated,
}),
`Clone ${name}`
)
))
}
</Menu.MenuItem>
));
};
export default definePlugin({ export default definePlugin({
name: "EmoteCloner", name: "EmoteCloner",
description: "Allows you to clone Emotes & Stickers to your own server (right click them)", description: "Allows you to clone Emotes & Stickers to your own server (right click them)",
tags: ["StickerCloner"], tags: ["StickerCloner"],
authors: [Devs.Ven, Devs.Nuckyz], authors: [Devs.Ven, Devs.Nuckyz, Devs.sadan],
contextMenus: { contextMenus: {
"message": messageContextMenuPatch, "message": messageContextMenuPatch,
"expression-picker": expressionPickerPatch "expression-picker": expressionPickerPatch,
} "image-context": imageContextPatch,
"channel-context": channelContextStatusPatch
},
}); });

View file

@ -0,0 +1,5 @@
# FullSearchContext
Makes the message context menu in message search results have all options you'd expect.
![](https://github.com/user-attachments/assets/472d1327-3935-44c7-b7c4-0978b5348550)

View file

@ -0,0 +1,82 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { migratePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack";
import { ChannelStore, ContextMenuApi, i18n, UserStore } from "@webpack/common";
import { Message } from "discord-types/general";
import type { MouseEvent } from "react";
const { useMessageMenu } = findByPropsLazy("useMessageMenu");
function MessageMenu({ message, channel, onHeightUpdate }) {
const canReport = message.author &&
!(message.author.id === UserStore.getCurrentUser().id || message.author.system);
return useMessageMenu({
navId: "message-actions",
ariaLabel: i18n.Messages.MESSAGE_UTILITIES_A11Y_LABEL,
message,
channel,
canReport,
onHeightUpdate,
onClose: () => ContextMenuApi.closeContextMenu(),
textSelection: "",
favoriteableType: null,
favoriteableId: null,
favoriteableName: null,
itemHref: void 0,
itemSrc: void 0,
itemSafeSrc: void 0,
itemTextContent: void 0,
});
}
migratePluginSettings("FullSearchContext", "SearchReply");
export default definePlugin({
name: "FullSearchContext",
description: "Makes the message context menu in message search results have all options you'd expect",
authors: [Devs.Ven, Devs.Aria],
patches: [{
find: "onClick:this.handleMessageClick,",
replacement: {
match: /this(?=\.handleContextMenu\(\i,\i\))/,
replace: "$self"
}
}],
handleContextMenu(event: MouseEvent, message: Message) {
const channel = ChannelStore.getChannel(message.channel_id);
if (!channel) return;
event.stopPropagation();
ContextMenuApi.openContextMenu(event, contextMenuProps =>
<MessageMenu
message={message}
channel={channel}
onHeightUpdate={contextMenuProps.onHeightUpdate}
/>
);
}
});

View file

@ -1,6 +0,0 @@
# SearchReply
Adds a reply button to search results.
![the plugin in action](https://github.com/Vendicated/Vencord/assets/45497981/07e741d3-0f97-4e5c-82b0-80712ecf2cbb)

View file

@ -1,75 +0,0 @@
/*
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2023 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { ReplyIcon } from "@components/Icons";
import { Devs } from "@utils/constants";
import definePlugin from "@utils/types";
import { findByCodeLazy } from "@webpack";
import { ChannelStore, i18n, Menu, PermissionsBits, PermissionStore, SelectedChannelStore } from "@webpack/common";
import { Message } from "discord-types/general";
const replyToMessage = findByCodeLazy(".TEXTAREA_FOCUS)", "showMentionToggle:");
const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { message }: { message: Message; }) => {
// make sure the message is in the selected channel
if (SelectedChannelStore.getChannelId() !== message.channel_id) return;
const channel = ChannelStore.getChannel(message?.channel_id);
if (!channel) return;
if (channel.guild_id && !PermissionStore.can(PermissionsBits.SEND_MESSAGES, channel)) return;
// dms and group chats
const dmGroup = findGroupChildrenByChildId("pin", children);
if (dmGroup && !dmGroup.some(child => child?.props?.id === "reply")) {
const pinIndex = dmGroup.findIndex(c => c?.props.id === "pin");
dmGroup.splice(pinIndex + 1, 0, (
<Menu.MenuItem
id="reply"
label={i18n.Messages.MESSAGE_ACTION_REPLY}
icon={ReplyIcon}
action={(e: React.MouseEvent) => replyToMessage(channel, message, e)}
/>
));
return;
}
// servers
const serverGroup = findGroupChildrenByChildId("mark-unread", children);
if (serverGroup && !serverGroup.some(child => child?.props?.id === "reply")) {
serverGroup.unshift((
<Menu.MenuItem
id="reply"
label={i18n.Messages.MESSAGE_ACTION_REPLY}
icon={ReplyIcon}
action={(e: React.MouseEvent) => replyToMessage(channel, message, e)}
/>
));
return;
}
};
export default definePlugin({
name: "SearchReply",
description: "Adds a reply button to search results",
authors: [Devs.Aria],
contextMenus: {
"message": messageContextMenuPatch
}
});