Compare commits

..

7 commits

6 changed files with 51 additions and 12 deletions

View file

@ -90,19 +90,20 @@ export function removeGlobalContextMenuPatch(patch: GlobalContextMenuPatchCallba
* A helper function for finding the children array of a group nested inside a context menu based on the id(s) of its children * A helper function for finding the children array of a group nested inside a context menu based on the id(s) of its children
* @param id The id of the child. If an array is specified, all ids will be tried * @param id The id of the child. If an array is specified, all ids will be tried
* @param children The context menu children * @param children The context menu children
* @param matchSubstring Whether to check if the id is a substring of the child id
*/ */
export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null>): Array<ReactElement | null> | null { export function findGroupChildrenByChildId(id: string | string[], children: Array<ReactElement | null | undefined>, matchSubstring = false): Array<ReactElement | null | undefined> | null {
for (const child of children) { for (const child of children) {
if (child == null) continue; if (child == null) continue;
if (Array.isArray(child)) { if (Array.isArray(child)) {
const found = findGroupChildrenByChildId(id, child); const found = findGroupChildrenByChildId(id, child, matchSubstring);
if (found !== null) return found; if (found !== null) return found;
} }
if ( if (
(Array.isArray(id) && id.some(id => child.props?.id === id)) (Array.isArray(id) && id.some(id => matchSubstring ? child.props?.id?.includes(id) : child.props?.id === id))
|| child.props?.id === id || (matchSubstring ? child.props?.id?.includes(id) : child.props?.id === id)
) return children; ) return children;
let nextChildren = child.props?.children; let nextChildren = child.props?.children;
@ -112,7 +113,7 @@ export function findGroupChildrenByChildId(id: string | string[], children: Arra
child.props.children = nextChildren; child.props.children = nextChildren;
} }
const found = findGroupChildrenByChildId(id, nextChildren); const found = findGroupChildrenByChildId(id, nextChildren, matchSubstring);
if (found !== null) return found; if (found !== null) return found;
} }
} }

View file

@ -200,8 +200,8 @@ export default definePlugin({
predicate: () => settings.store.sidebar, predicate: () => settings.store.sidebar,
replacement: { replacement: {
// Render the Better Folders sidebar // Render the Better Folders sidebar
match: /(?<=({className:\i\.guilds,themeOverride:\i})\))/, match: /(container.{0,50}({className:\i\.guilds,themeOverride:\i})\))/,
replace: ",$self.FolderSideBar({...$1})" replace: "$1,$self.FolderSideBar({...$2})"
} }
}, },
{ {

View file

@ -203,6 +203,15 @@ export default definePlugin({
settings, settings,
patches: [ patches: [
// Patch the emoji picker in voice calls to not be bypassed by fake nitro
{
find: "emojiItemDisabled]",
predicate: () => settings.store.enableEmojiBypass,
replacement: {
match: /CHAT/,
replace: "STATUS"
}
},
{ {
find: ".PREMIUM_LOCKED;", find: ".PREMIUM_LOCKED;",
group: true, group: true,

View file

@ -16,16 +16,25 @@
* 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 { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/ContextMenu";
import { migratePluginSettings } from "@api/Settings"; import { migratePluginSettings } from "@api/Settings";
import { Devs } from "@utils/constants"; import { Devs } from "@utils/constants";
import { NoopComponent } from "@utils/react";
import definePlugin from "@utils/types"; import definePlugin from "@utils/types";
import { findByPropsLazy } from "@webpack"; import { filters, findByPropsLazy, waitFor } from "@webpack";
import { ChannelStore, ContextMenuApi, i18n, UserStore } from "@webpack/common"; import { ChannelStore, ContextMenuApi, i18n, UserStore } from "@webpack/common";
import { Message } from "discord-types/general"; import { Message } from "discord-types/general";
import type { MouseEvent } from "react";
const { useMessageMenu } = findByPropsLazy("useMessageMenu"); const { useMessageMenu } = findByPropsLazy("useMessageMenu");
interface CopyIdMenuItemProps {
id: string;
label: string;
}
let CopyIdMenuItem: (props: CopyIdMenuItemProps) => React.ReactElement | null = NoopComponent;
waitFor(filters.componentByCode('"devmode-copy-id-".concat'), m => CopyIdMenuItem = m);
function MessageMenu({ message, channel, onHeightUpdate }) { function MessageMenu({ message, channel, onHeightUpdate }) {
const canReport = message.author && const canReport = message.author &&
!(message.author.id === UserStore.getCurrentUser().id || message.author.system); !(message.author.id === UserStore.getCurrentUser().id || message.author.system);
@ -48,9 +57,25 @@ function MessageMenu({ message, channel, onHeightUpdate }) {
itemSrc: void 0, itemSrc: void 0,
itemSafeSrc: void 0, itemSafeSrc: void 0,
itemTextContent: void 0, itemTextContent: void 0,
isFullSearchContextMenu: true
}); });
} }
interface MessageActionsProps {
message: Message;
isFullSearchContextMenu?: boolean;
}
const contextMenuPatch: NavContextMenuPatchCallback = (children, props: MessageActionsProps) => {
if (props?.isFullSearchContextMenu == null) return;
const group = findGroupChildrenByChildId("devmode-copy-id", children, true);
group?.push(
CopyIdMenuItem({ id: props.message.author.id, label: i18n.Messages.COPY_ID_AUTHOR })
);
};
migratePluginSettings("FullSearchContext", "SearchReply"); migratePluginSettings("FullSearchContext", "SearchReply");
export default definePlugin({ export default definePlugin({
name: "FullSearchContext", name: "FullSearchContext",
@ -65,7 +90,7 @@ export default definePlugin({
} }
}], }],
handleContextMenu(event: MouseEvent, message: Message) { handleContextMenu(event: React.MouseEvent, message: Message) {
const channel = ChannelStore.getChannel(message.channel_id); const channel = ChannelStore.getChannel(message.channel_id);
if (!channel) return; if (!channel) return;
@ -78,5 +103,9 @@ export default definePlugin({
onHeightUpdate={contextMenuProps.onHeightUpdate} onHeightUpdate={contextMenuProps.onHeightUpdate}
/> />
); );
},
contextMenus: {
"message-actions": contextMenuPatch
} }
}); });

View file

@ -61,8 +61,7 @@ const settings = definePluginSettings({
type: OptionType.SLIDER, type: OptionType.SLIDER,
description: "Intensity of message coloring.", description: "Intensity of message coloring.",
markers: makeRange(0, 100, 10), markers: makeRange(0, 100, 10),
default: 30, default: 30
restartNeeded: true
}, },
}); });

View file

@ -51,6 +51,7 @@ export default definePlugin({
name: "UserVoiceShow", name: "UserVoiceShow",
description: "Shows an indicator when a user is in a Voice Channel", description: "Shows an indicator when a user is in a Voice Channel",
authors: [Devs.Nuckyz, Devs.LordElias], authors: [Devs.Nuckyz, Devs.LordElias],
dependencies: ["MemberListDecoratorsAPI", "MessageDecorationsAPI"],
settings, settings,
patches: [ patches: [