[UI > QuickInstall] Add pop-up when clicking on links (#67)
This commit is contained in:
parent
3448a3b2cb
commit
ea775736a2
6 changed files with 88 additions and 46 deletions
5
src/def.d.ts
vendored
5
src/def.d.ts
vendored
|
@ -76,11 +76,14 @@ export enum ButtonColors {
|
||||||
|
|
||||||
interface ConfirmationAlertOptions {
|
interface ConfirmationAlertOptions {
|
||||||
title?: string;
|
title?: string;
|
||||||
content: string | JSX.Element | JSX.Element[];
|
content: string | JSX.Element | (string | JSX.Element)[];
|
||||||
confirmText?: string;
|
confirmText?: string;
|
||||||
confirmColor?: ButtonColors;
|
confirmColor?: ButtonColors;
|
||||||
onConfirm: () => void;
|
onConfirm: () => void;
|
||||||
|
secondaryConfirmText?: string;
|
||||||
|
onConfirmSecondary?: () => void;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
isDismissable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InputAlertProps {
|
interface InputAlertProps {
|
||||||
|
|
|
@ -5,21 +5,18 @@ import InputAlert from "@ui/components/InputAlert";
|
||||||
const Alerts = findByProps("openLazy", "close");
|
const Alerts = findByProps("openLazy", "close");
|
||||||
|
|
||||||
interface InternalConfirmationAlertOptions extends Omit<ConfirmationAlertOptions, "content"> {
|
interface InternalConfirmationAlertOptions extends Omit<ConfirmationAlertOptions, "content"> {
|
||||||
content: string | JSX.Element | JSX.Element[] | undefined;
|
content?: ConfirmationAlertOptions["content"];
|
||||||
body: string | undefined;
|
body?: ConfirmationAlertOptions["content"];
|
||||||
children: JSX.Element | JSX.Element[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function showConfirmationAlert(options: ConfirmationAlertOptions) {
|
export function showConfirmationAlert(options: ConfirmationAlertOptions) {
|
||||||
const internalOptions = options as InternalConfirmationAlertOptions;
|
const internalOptions = options as InternalConfirmationAlertOptions;
|
||||||
|
|
||||||
if (typeof options.content === "string") {
|
internalOptions.body = options.content;
|
||||||
internalOptions.body = options.content;
|
|
||||||
} else {
|
|
||||||
internalOptions.children = options.content;
|
|
||||||
};
|
|
||||||
|
|
||||||
delete internalOptions.content;
|
delete internalOptions.content;
|
||||||
|
|
||||||
|
internalOptions.isDismissable ??= true;
|
||||||
|
|
||||||
return Alerts.show(internalOptions);
|
return Alerts.show(internalOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -27,4 +24,4 @@ export const showCustomAlert = (component: React.ComponentType, props: any) => A
|
||||||
importer: async () => () => React.createElement(component, props),
|
importer: async () => () => React.createElement(component, props),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const showInputAlert = (options: InputAlertProps) => showCustomAlert(InputAlert as React.ComponentType, options);
|
export const showInputAlert = (options: InputAlertProps) => showCustomAlert(InputAlert as React.ComponentType, options);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
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 { DISCORD_SERVER_ID, PLUGINS_CHANNEL_ID, THEMES_CHANNEL_ID, HTTP_REGEX_MULTI, PROXY_PREFIX } from "@lib/constants";
|
||||||
|
import { findByName, findByProps } from "@metro/filters";
|
||||||
import { after } from "@lib/patcher";
|
import { after } from "@lib/patcher";
|
||||||
import { installPlugin } from "@lib/plugins";
|
import { installPlugin } from "@lib/plugins";
|
||||||
import { installTheme } from "@lib/themes";
|
import { installTheme } from "@lib/themes";
|
||||||
|
@ -20,7 +20,7 @@ export default () => after("default", ForumPostLongPressActionSheet, ([{ thread
|
||||||
if (thread.guild_id !== DISCORD_SERVER_ID) return;
|
if (thread.guild_id !== DISCORD_SERVER_ID) return;
|
||||||
|
|
||||||
// Determine what type of addon this is.
|
// Determine what type of addon this is.
|
||||||
let postType: string;
|
let postType: "Plugin" | "Theme";
|
||||||
if (thread.parent_id === PLUGINS_CHANNEL_ID) {
|
if (thread.parent_id === PLUGINS_CHANNEL_ID) {
|
||||||
postType = "Plugin";
|
postType = "Plugin";
|
||||||
} else if (thread.parent_id === THEMES_CHANNEL_ID && window.__vendetta_loader?.features.themes) {
|
} else if (thread.parent_id === THEMES_CHANNEL_ID && window.__vendetta_loader?.features.themes) {
|
||||||
|
@ -62,4 +62,4 @@ export default () => after("default", ForumPostLongPressActionSheet, ([{ thread
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ActionsSection>);
|
</ActionsSection>);
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,4 +8,4 @@ export default function initQuickInstall() {
|
||||||
patches.push(patchUrl());
|
patches.push(patchUrl());
|
||||||
|
|
||||||
return () => patches.forEach(p => p());
|
return () => patches.forEach(p => p());
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
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, (args) => {
|
|
||||||
if (args[0].key !== "LongPressUrl") return;
|
|
||||||
|
|
||||||
const { header: { title: url }, options } = args[0];
|
|
||||||
|
|
||||||
let urlType: string;
|
|
||||||
if (url.startsWith(PROXY_PREFIX)) {
|
|
||||||
urlType = "Plugin";
|
|
||||||
} else if (url.endsWith(".json") && window.__vendetta_loader?.features.themes) {
|
|
||||||
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"));
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
});
|
|
73
src/ui/quickInstall/url.tsx
Normal file
73
src/ui/quickInstall/url.tsx
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
import { PROXY_PREFIX, THEMES_CHANNEL_ID } from "@lib/constants";
|
||||||
|
import { findByProps } from "@metro/filters";
|
||||||
|
import { ReactNative as RN, channels, url } from "@metro/common";
|
||||||
|
import { after, instead } from "@lib/patcher";
|
||||||
|
import { installPlugin } from "@lib/plugins";
|
||||||
|
import { installTheme } from "@lib/themes";
|
||||||
|
import { getAssetIDByName } from "@ui/assets";
|
||||||
|
import { showToast } from "@ui/toasts";
|
||||||
|
import { showConfirmationAlert } from "../alerts";
|
||||||
|
|
||||||
|
const showSimpleActionSheet = findByProps("showSimpleActionSheet");
|
||||||
|
const handleClick = findByProps("handleClick");
|
||||||
|
const { openURL } = url;
|
||||||
|
const { getChannelId } = channels;
|
||||||
|
const { getChannel } = findByProps("getChannel");
|
||||||
|
|
||||||
|
const { TextStyleSheet } = findByProps("TextStyleSheet");
|
||||||
|
|
||||||
|
function typeFromUrl(url: string) {
|
||||||
|
if (url.startsWith(PROXY_PREFIX)) {
|
||||||
|
return "Plugin";
|
||||||
|
} else if (url.endsWith(".json") && window.__vendetta_loader?.features.themes) {
|
||||||
|
return "Theme";
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function installWithToast(type: "Plugin" | "Theme", url: string) {
|
||||||
|
(type === "Plugin" ? installPlugin : installTheme)(url).then(() => {
|
||||||
|
showToast("Successfully installed", getAssetIDByName("Check"));
|
||||||
|
}).catch((e: Error) => {
|
||||||
|
showToast(e.message, getAssetIDByName("Small"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const patches = new Array<Function>;
|
||||||
|
|
||||||
|
patches.push(after("showSimpleActionSheet", showSimpleActionSheet, (args) => {
|
||||||
|
if (args[0].key !== "LongPressUrl") return;
|
||||||
|
const { header: { title: url }, options } = args[0];
|
||||||
|
|
||||||
|
const urlType = typeFromUrl(url);
|
||||||
|
if (!urlType) return;
|
||||||
|
|
||||||
|
options.push({
|
||||||
|
label: `Install ${urlType}`,
|
||||||
|
onPress: () => installWithToast(urlType, url),
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
patches.push(instead("handleClick", handleClick, async function (this: any, args, orig) {
|
||||||
|
const { href: url } = args[0];
|
||||||
|
|
||||||
|
const urlType = typeFromUrl(url);
|
||||||
|
if (!urlType) return orig.apply(this, args);
|
||||||
|
|
||||||
|
// Make clicking on theme links only work in #themes, should there be a theme proxy in the future, this can be removed.
|
||||||
|
if (urlType === "Theme" && getChannel(getChannelId())?.parent_id !== THEMES_CHANNEL_ID)
|
||||||
|
return orig.apply(this, args);
|
||||||
|
|
||||||
|
showConfirmationAlert({
|
||||||
|
title: "Hold Up",
|
||||||
|
content: [`This link is a `, <RN.Text style={TextStyleSheet["text-md/semibold"]}>{urlType}</RN.Text>, `, would you like to install it?`],
|
||||||
|
onConfirm: () => installWithToast(urlType, url),
|
||||||
|
confirmText: "Install",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
secondaryConfirmText: "Open in Browser",
|
||||||
|
onConfirmSecondary: () => openURL(url),
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
return () => patches.forEach((p) => p());
|
||||||
|
};
|
Loading…
Reference in a new issue