[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:
parent
3082c840c8
commit
5148fdb15f
6 changed files with 118 additions and 1 deletions
5
src/def.d.ts
vendored
5
src/def.d.ts
vendored
|
@ -369,8 +369,13 @@ interface VendettaObject {
|
||||||
};
|
};
|
||||||
constants: {
|
constants: {
|
||||||
DISCORD_SERVER: string;
|
DISCORD_SERVER: string;
|
||||||
|
DISCORD_SERVER_ID: string;
|
||||||
|
PLUGINS_CHANNEL_ID: string;
|
||||||
|
THEMES_CHANNEL_ID: string;
|
||||||
GITHUB: string;
|
GITHUB: string;
|
||||||
|
PROXY_PREFIX: string;
|
||||||
HTTP_REGEX: RegExp;
|
HTTP_REGEX: RegExp;
|
||||||
|
HTTP_REGEX_MULTI: RegExp;
|
||||||
};
|
};
|
||||||
utils: {
|
utils: {
|
||||||
findInReactTree: (tree: SearchTree, filter: SearchFilter) => any;
|
findInReactTree: (tree: SearchTree, filter: SearchFilter) => any;
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { patchLogHook } from "@lib/debug";
|
||||||
import { patchCommands } from "@lib/commands";
|
import { patchCommands } from "@lib/commands";
|
||||||
import { initPlugins } from "@lib/plugins";
|
import { initPlugins } from "@lib/plugins";
|
||||||
import { patchAssets } from "@ui/assets";
|
import { patchAssets } from "@ui/assets";
|
||||||
|
import initQuickInstall from "@ui/quickInstall";
|
||||||
import initSettings from "@ui/settings";
|
import initSettings from "@ui/settings";
|
||||||
import initFixes from "@lib/fixes";
|
import initFixes from "@lib/fixes";
|
||||||
import logger from "@lib/logger";
|
import logger from "@lib/logger";
|
||||||
|
@ -15,6 +16,7 @@ export default async () => {
|
||||||
patchCommands(),
|
patchCommands(),
|
||||||
initFixes(),
|
initFixes(),
|
||||||
initSettings(),
|
initSettings(),
|
||||||
|
initQuickInstall(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Assign window object
|
// Assign window object
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
export const DISCORD_SERVER = "https://discord.gg/n9QQ4XhhJP";
|
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 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;
|
65
src/ui/quickInstall/forumPost.tsx
Normal file
65
src/ui/quickInstall/forumPost.tsx
Normal 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>);
|
||||||
|
});
|
11
src/ui/quickInstall/index.ts
Normal file
11
src/ui/quickInstall/index.ts
Normal 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());
|
||||||
|
};
|
29
src/ui/quickInstall/url.ts
Normal file
29
src/ui/quickInstall/url.ts
Normal 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"));
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue