Skip to content

Commit

Permalink
Merge branch 'main' into auto-relaunch
Browse files Browse the repository at this point in the history
  • Loading branch information
yofukashino authored Nov 11, 2024
2 parents dab08db + 1df7737 commit 6e166ff
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 197 deletions.
5 changes: 3 additions & 2 deletions src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { getSetting } from "./ipc/settings";

const electronPath = require.resolve("electron");
const discordPath = join(dirname(require.main!.filename), "..", "app.orig.asar");
// require.main!.filename = discordMain;
const discordPackage = require(join(discordPath, "package.json"));
require.main!.filename = join(discordPath, discordPackage.main);

Object.defineProperty(global, "appSettings", {
set: (v /* : typeof global.appSettings*/) => {
Expand Down Expand Up @@ -185,4 +186,4 @@ electron.app.once("ready", () => {
// This module is required this way at runtime.
require("./ipc");

require("module")._load(discordPath);
require(discordPath);
154 changes: 69 additions & 85 deletions src/renderer/coremods/contextMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { React, components } from "@common";
import type { ContextMenuProps } from "@components/ContextMenu";
import { React, components, lodash } from "@common";
import type { MenuProps } from "@components/ContextMenu";
import type {
ContextItem,
ContextMenuTypes,
GetContextItem,
RawContextItem,
Expand All @@ -10,37 +9,35 @@ import { Logger } from "../../modules/logger";

const logger = Logger.api("ContextMenu");

export const menuItems = {} as Record<
ContextMenuTypes,
| Array<{ getItem: GetContextItem; sectionId: number | undefined; indexInSection: number }>
| undefined
>;
interface MenuItem {
getItem: GetContextItem;
sectionId: number | ((props: ContextMenuProps) => number) | undefined;
indexInSection: number | ((props: ContextMenuProps) => number);
}

export type ContextMenuProps = MenuProps & {
data: Array<Record<string, unknown>>;
};

export const menuItems: Record<string, MenuItem[] | undefined> = {};

/**
* Converts data into a React element. Any elements or falsy value will be returned as is
* @param raw The data to convert
* @returns The converted item
*/
function makeItem(raw: RawContextItem | ContextItem | undefined | void): ContextItem | undefined {
// Occasionally React won't be loaded when this function is ran, so we don't return anything
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!React) return undefined;

if (!raw) {
// If something falsy is passed, let it through
// Discord just skips over them too
return raw as ContextItem | undefined;
}
if (React.isValidElement(raw)) {
// We can't construct something that's already made
return raw as ContextItem | undefined;
}
function makeItem(raw: ReturnType<GetContextItem>): React.ReactElement | undefined {
if (!raw) return;
if (React.isValidElement(raw)) return raw;

const { type, ...props } = raw;
if (props.children) {
props.children = props.children.map((child: RawContextItem | ContextItem | undefined) =>
makeItem(child),
);
const { type, ...props } = raw as RawContextItem;

if ("children" in props && props.children) {
if (Array.isArray(props.children)) {
props.children = props.children.map((child: ReturnType<GetContextItem>) => makeItem(child));
} else {
props.children = makeItem(props.children as ReturnType<GetContextItem>);
}
}

return React.createElement(type as React.FC, props as Record<string, unknown>);
Expand All @@ -50,15 +47,15 @@ function makeItem(raw: RawContextItem | ContextItem | undefined | void): Context
* Add an item to any context menu
* @param navId The id of the menu you want to insert to
* @param getItem A function that creates and returns the menu item
* @param sectionId The number of the section to add to. Defaults to replugged's section
* @param sectionId The number of the section to add to. Defaults to Replugged's section
* @param indexInSection The index in the section to add to. Defaults to the end position
* @returns A callback to de-register the function
*/
export function addContextMenuItem(
navId: ContextMenuTypes,
getItem: GetContextItem,
sectionId: number | undefined,
indexInSection: number,
sectionId: number | ((props: ContextMenuProps) => number) | undefined,
indexInSection: number | ((props: ContextMenuProps) => number),
): () => void {
menuItems[navId] ||= [];

Expand All @@ -76,75 +73,62 @@ export function removeContextMenuItem(navId: ContextMenuTypes, getItem: GetConte
menuItems[navId] = menuItems[navId]?.filter((item) => item.getItem !== getItem);
}

type ContextMenuData = ContextMenuProps["ContextMenu"] & {
children: React.ReactElement | React.ReactElement[];
data: Array<Record<string, unknown>>;
navId: ContextMenuTypes;
plugged?: boolean;
};

/**
* @internal
* @hidden
*/
export function _insertMenuItems(menu: ContextMenuData): void {
const { navId } = menu;

// No items to insert
if (!menuItems[navId]) return;
export function _insertMenuItems(props: ContextMenuProps): ContextMenuProps {
const menuItemsPatches = menuItems[props.navId];
if (!menuItemsPatches) return props;

// Already inserted items
// If this isn't here, another group of items is added every update
if (menu.plugged) return;
props = {
...props,
// Shallow clone the children array and objects
children: lodash.cloneDeep(props.children),
};

// We delay getting the items until now, as importing at the start of the file causes Discord to hang
// Using `await import(...)` is undesirable because the new items will only appear once the menu is interacted with
const { MenuGroup } = components;
//if (!MenuGroup) return;

// The data as passed as Arguments from the calling function, so we just grab what we want from it
const data = menu.data[0];

const repluggedGroup = <MenuGroup />;
repluggedGroup.props.id = "replugged";
repluggedGroup.props.children = [];

// Add in the new menu items right above the DevMode Copy ID
// If the user doesn't have DevMode enabled, the new items will be at the bottom
if (!Array.isArray(menu.children)) menu.children = [menu.children];
const hasCopyId = menu.children
.at(-1)
?.props?.children?.props?.id?.startsWith("devmode-copy-id-");
if (hasCopyId) {
menu.children.splice(-1, 0, repluggedGroup);
} else {
menu.children.push(repluggedGroup);
}
if (!Array.isArray(props.children)) props.children = [props.children];

menuItems[navId]?.forEach((item) => {
menuItemsPatches.forEach(({ getItem, sectionId, indexInSection }) => {
try {
const res = makeItem(item.getItem(data, menu)) as
| (ContextItem & { props: { id?: string } })
| undefined;
if (res?.props) {
// add in unique ids
res.props.id = `${res.props.id || "repluggedItem"}-${Math.random()
.toString(36)
.substring(2)}`;
}

if (!Array.isArray(menu.children)) menu.children = [menu.children];
const section =
typeof item.sectionId === "undefined" ? repluggedGroup : menu.children.at(item.sectionId);
if (!section) {
logger.error("Couldn't find section", item.sectionId, menu.children);
return;
const item = makeItem(getItem(props.data[0], props));
if (!item) return;

if (sectionId !== undefined && Array.isArray(props.children)) {
sectionId = typeof sectionId === "function" ? sectionId(props) : sectionId;
const section = props.children.at(sectionId);

if (!section) {
logger.error("Couldn't find section", sectionId, props.children);
return;
}

if (!Array.isArray(section.props.children))
section.props.children = [section.props.children];

indexInSection =
typeof indexInSection === "function" ? indexInSection(props) : indexInSection;
section.props.children.splice(indexInSection, 0, item);
} else {
repluggedGroup.props.children.push(item);
}
section.props.children.splice(item.indexInSection, 0, res);
} catch (err) {
logger.error("Error while running GetContextItem function", err, item.getItem);
} catch (e) {
logger.error(`Failed to add item to menu ${props.navId}`, e);
}
});

menu.plugged = true;
const hasCopyId = props.children
.at(-1)
?.props?.children?.props?.id?.startsWith("devmode-copy-id-");
if (hasCopyId) {
props.children.splice(-1, 0, repluggedGroup);
} else {
props.children.push(repluggedGroup);
}

return props;
}
6 changes: 3 additions & 3 deletions src/renderer/coremods/contextMenu/plaintextPatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import type { PlaintextPatch } from "src/types";

export default [
{
find: 'Error("Menu',
find: "♫ (つ。◕‿‿◕。)つ ♪",
replacements: [
{
match: /((\w+)\){)(var\s*\w+;let{navId:)/,
replace: (_, prefix, menu, suffix) =>
`${prefix}replugged.coremods.coremods.contextMenu._insertMenuItems(${menu});${suffix}`,
replace: (_, prefix, props, suffix) =>
`${prefix}${props}=replugged.coremods.coremods.contextMenu._insertMenuItems(${props});${suffix}`,
},
],
},
Expand Down
Loading

0 comments on commit 6e166ff

Please sign in to comment.