[UI > QuickInstall] Implement (#45)

* [UI > QuickInstall] Init

* [Constants] Update PROXY_PREFIX

* [TS] Type additional constants

* [Style] Move Metro filter imports to top of imports
This commit is contained in:
Jack 2023-04-03 20:35:59 -04:00 committed by GitHub
parent 3082c840c8
commit 5148fdb15f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 118 additions and 1 deletions

5
src/def.d.ts vendored
View file

@ -369,8 +369,13 @@ interface VendettaObject {
};
constants: {
DISCORD_SERVER: string;
DISCORD_SERVER_ID: string;
PLUGINS_CHANNEL_ID: string;
THEMES_CHANNEL_ID: string;
GITHUB: string;
PROXY_PREFIX: string;
HTTP_REGEX: RegExp;
HTTP_REGEX_MULTI: RegExp;
};
utils: {
findInReactTree: (tree: SearchTree, filter: SearchFilter) => any;

View file

@ -2,6 +2,7 @@ import { patchLogHook } from "@lib/debug";
import { patchCommands } from "@lib/commands";
import { initPlugins } from "@lib/plugins";
import { patchAssets } from "@ui/assets";
import initQuickInstall from "@ui/quickInstall";
import initSettings from "@ui/settings";
import initFixes from "@lib/fixes";
import logger from "@lib/logger";
@ -15,6 +16,7 @@ export default async () => {
patchCommands(),
initFixes(),
initSettings(),
initQuickInstall(),
]);
// Assign window object

View file

@ -1,3 +1,8 @@
export const DISCORD_SERVER = "https://discord.gg/n9QQ4XhhJP";
export const DISCORD_SERVER_ID = "1015931589865246730";
export const PLUGINS_CHANNEL_ID = "1091880384561684561";
export const THEMES_CHANNEL_ID = "1091880434939482202";
export const GITHUB = "https://github.com/vendetta-mod";
export const HTTP_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/;
export const PROXY_PREFIX = "https://vd-plugins.github.io/proxy";
export const HTTP_REGEX = /^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/;
export const HTTP_REGEX_MULTI = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;

View file

@ -0,0 +1,65 @@
import { findByName, findByProps } from "@metro/filters";
import { DISCORD_SERVER_ID, PLUGINS_CHANNEL_ID, THEMES_CHANNEL_ID, HTTP_REGEX_MULTI, PROXY_PREFIX } from "@lib/constants";
import { after } from "@lib/patcher";
import { installPlugin } from "@lib/plugins";
import { installTheme } from "@lib/themes";
import { findInReactTree } from "@lib/utils";
import { getAssetIDByName } from "@ui/assets";
import { Forms } from "@ui/components";
import { showToast } from "@ui/toasts";
const ForumPostLongPressActionSheet = findByName("ForumPostLongPressActionSheet", false);
const { FormRow } = Forms;
// Discord uses this Icon in action sheets. FormRow.Icon is too dark.
const Icon = findByName("Icon");
const { useFirstForumPostMessage } = findByProps("useFirstForumPostMessage");
const { hideActionSheet } = findByProps("openLazy", "hideActionSheet");
export default () => after("default", ForumPostLongPressActionSheet, ([{ thread }], res) => {
if (thread.guild_id !== DISCORD_SERVER_ID) return;
// Determine what type of addon this is.
let postType: string;
if (thread.parent_id === PLUGINS_CHANNEL_ID) {
postType = "Plugin";
} else if (thread.parent_id === THEMES_CHANNEL_ID) {
postType = "Theme";
} else return;
const { firstMessage } = useFirstForumPostMessage(thread);
let urls = firstMessage?.content?.match(HTTP_REGEX_MULTI);
if (!urls) return;
if (postType === "Plugin") {
urls = urls.filter((url: string) => url.startsWith(PROXY_PREFIX));
} else {
urls = urls.filter((url: string) => url.endsWith(".json"));
};
const url = urls[0];
if (!url) return;
/* Assuming that the actions array is at index 1
could break in the future, but I doubt Discord
will add more to the post action sheet and
index 0 will either be quick add reactions or false.
*/
const actions = findInReactTree(res, (t) => t.props?.bottom === true).props.children.props.children[1];
const ActionsSection = actions[0].type;
actions.unshift(<ActionsSection key="install">
<FormRow
leading={<Icon source={getAssetIDByName("ic_download_24px")} />}
label={`Install ${postType}`}
onPress={() =>
(postType === "Plugin" ? installPlugin : installTheme)(url).then(() => {
showToast(`Successfully installed ${thread.name}`, getAssetIDByName("Check"));
}).catch((e: Error) => {
showToast(e.message, getAssetIDByName("Small"));
}).finally(() => hideActionSheet())
}
/>
</ActionsSection>);
});

View file

@ -0,0 +1,11 @@
import patchForumPost from "@ui/quickInstall/forumPost";
import patchUrl from "@ui/quickInstall/url";
export default function initQuickInstall() {
const patches = new Array<Function>;
patches.push(patchForumPost());
patches.push(patchUrl());
return () => patches.forEach(p => p());
};

View file

@ -0,0 +1,29 @@
import { findByProps } from "@metro/filters";
import { PROXY_PREFIX } from "@lib/constants";
import { after } from "@lib/patcher";
import { installPlugin } from "@lib/plugins";
import { installTheme } from "@lib/themes";
import { getAssetIDByName } from "@ui/assets";
import { showToast } from "@ui/toasts";
const showSimpleActionSheet = findByProps("showSimpleActionSheet");
export default () => after("showSimpleActionSheet", showSimpleActionSheet, ([{ key, header: { title: url }, options }]) => {
if (key !== "LongPressUrl") return;
let urlType: string;
if (url.startsWith(PROXY_PREFIX)) {
urlType = "Plugin";
} else if (url.endsWith(".json")) {
urlType = "Theme";
} else return;
options.push({
label: `Install ${urlType}`, onPress: () =>
(urlType === "Plugin" ? installPlugin : installTheme)(url).then(() => {
showToast("Successfully installed", getAssetIDByName("Check"));
}).catch((e: Error) => {
showToast(e.message, getAssetIDByName("Small"));
}),
});
});