refactor: expose more stuff and move some stuff
This commit is contained in:
parent
fe937a4ab5
commit
f2f1f6ac73
53 changed files with 248 additions and 407 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import { PluginInstanceInternal } from "@lib/plugins/types";
|
||||
import { PluginInstanceInternal } from "@lib/addons/plugins/types";
|
||||
|
||||
interface CorePlugin {
|
||||
default: PluginInstanceInternal;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import { findAssetId } from "@lib/api/assets";
|
|||
import { isThemeSupported } from "@lib/api/native/loader";
|
||||
import { after } from "@lib/api/patcher";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { installTheme, removeTheme, themes } from "@lib/themes";
|
||||
import { DISCORD_SERVER_ID, HTTP_REGEX_MULTI, PLUGINS_CHANNEL_ID, THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { installTheme, removeTheme, themes } from "@lib/addons/themes";
|
||||
import { VD_DISCORD_SERVER_ID, HTTP_REGEX_MULTI, VD_PLUGINS_CHANNEL_ID, VD_THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { Button } from "@metro/common/components";
|
||||
import { findByProps, findByPropsLazy } from "@metro/wrappers";
|
||||
|
|
@ -39,13 +39,13 @@ const postMap = {
|
|||
};
|
||||
|
||||
function useExtractThreadContent(thread: any, _firstMessage = null, actionSheet = false): ([PostType, string]) | void {
|
||||
if (thread.guild_id !== DISCORD_SERVER_ID) return;
|
||||
if (thread.guild_id !== VD_DISCORD_SERVER_ID) return;
|
||||
|
||||
// Determine what type of addon this is.
|
||||
let postType: PostType;
|
||||
if (thread.parent_id === PLUGINS_CHANNEL_ID) {
|
||||
if (thread.parent_id === VD_PLUGINS_CHANNEL_ID) {
|
||||
postType = "Plugin";
|
||||
} else if (thread.parent_id === THEMES_CHANNEL_ID && isThemeSupported()) {
|
||||
} else if (thread.parent_id === VD_THEMES_CHANNEL_ID && isThemeSupported()) {
|
||||
postType = "Theme";
|
||||
} else return;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { VdPluginManager } from "@core/vendetta/plugins";
|
|||
import { findAssetId } from "@lib/api/assets";
|
||||
import { isThemeSupported } from "@lib/api/native/loader";
|
||||
import { after, instead } from "@lib/api/patcher";
|
||||
import { installTheme } from "@lib/themes";
|
||||
import { THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { installTheme } from "@lib/addons/themes";
|
||||
import { VD_THEMES_CHANNEL_ID, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { channels, url } from "@metro/common";
|
||||
import { byMutableProp } from "@metro/filters";
|
||||
import { findExports } from "@metro/finders";
|
||||
import { findByProps, findByPropsLazy } from "@metro/wrappers";
|
||||
import { showConfirmationAlert } from "@ui/alerts";
|
||||
import { showConfirmationAlert } from "@core/vendetta/alerts";
|
||||
import { showToast } from "@ui/toasts";
|
||||
|
||||
const showSimpleActionSheet = findExports(byMutableProp("showSimpleActionSheet"));
|
||||
|
|
@ -66,7 +66,7 @@ export default () => {
|
|||
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);
|
||||
if (urlType === "theme" && getChannel(getChannelId())?.parent_id !== VD_THEMES_CHANNEL_ID) return orig.apply(this, args);
|
||||
|
||||
showConfirmationAlert({
|
||||
title: Strings.HOLD_UP,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,7 @@ export default function initSettings() {
|
|||
title: () => Strings.BUNNY,
|
||||
icon: { uri: PyoncordIcon },
|
||||
render: () => import("@core/ui/settings/pages/General"),
|
||||
rawTabsConfig: {
|
||||
useTrailing: () => `(${version})`
|
||||
}
|
||||
useTrailing: () => `(${version})`
|
||||
},
|
||||
{
|
||||
key: "BUNNY_PLUGINS",
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ import { CardWrapper } from "@core/ui/components/AddonCard";
|
|||
import { findAssetId } from "@lib/api/assets";
|
||||
import { BundleUpdaterManager } from "@lib/api/native/modules";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { FontDefinition, fonts, selectFont } from "@lib/fonts";
|
||||
import { FontDefinition, fonts, selectFont } from "@lib/addons/fonts";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { findByProps } from "@metro";
|
||||
import { NavigationNative, tokens } from "@metro/common";
|
||||
import { Button, Card, IconButton, Stack, Text } from "@metro/common/components";
|
||||
import * as Skia from "@shopify/react-native-skia";
|
||||
import { showConfirmationAlert } from "@ui/alerts";
|
||||
import { showConfirmationAlert } from "@core/vendetta/alerts";
|
||||
import { TextStyleSheet } from "@ui/styles";
|
||||
import { useMemo } from "react";
|
||||
import { View } from "react-native";
|
||||
|
|
@ -104,7 +103,7 @@ export default function FontCard({ item: font }: CardWrapper<FontDefinition>) {
|
|||
content: "Reload Discord to apply changes?",
|
||||
confirmText: Strings.RELOAD,
|
||||
cancelText: Strings.CANCEL,
|
||||
confirmColor: ButtonColors.RED,
|
||||
confirmColor: "red",
|
||||
onConfirm: BundleUpdaterManager.reload
|
||||
});
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { formatString, Strings } from "@core/i18n";
|
||||
import { findAssetId } from "@lib/api/assets";
|
||||
import { createProxy, useProxy } from "@lib/api/storage";
|
||||
import { FontDefinition, fonts, removeFont, saveFont, validateFont } from "@lib/fonts";
|
||||
import { getCurrentTheme } from "@lib/themes";
|
||||
import { FontDefinition, fonts, removeFont, saveFont, validateFont } from "@lib/addons/fonts";
|
||||
import { getCurrentTheme } from "@lib/addons/themes";
|
||||
import { safeFetch } from "@lib/utils";
|
||||
import { NavigationNative } from "@metro/common";
|
||||
import { ActionSheet, BottomSheetTitleHeader, Button, IconButton, Stack, TableRow, TableRowGroup, Text, TextInput } from "@metro/common/components";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import AddonPage from "@core/ui/components/AddonPage";
|
|||
import FontEditor from "@core/ui/settings/pages/Fonts/FontEditor";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { FontDefinition, fonts } from "@lib/fonts";
|
||||
import { FontDefinition, fonts } from "@lib/addons/fonts";
|
||||
import { NavigationNative } from "@metro/common";
|
||||
|
||||
import FontCard from "./FontCard";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { findAssetId } from "@lib/api/assets";
|
||||
import { installPlugin, isPluginInstalled, uninstallPlugin } from "@lib/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/plugins/types";
|
||||
import { installPlugin, isPluginInstalled, uninstallPlugin } from "@lib/addons/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/addons/plugins/types";
|
||||
import { showToast } from "@lib/ui/toasts";
|
||||
import { safeFetch } from "@lib/utils";
|
||||
import { OFFICIAL_PLUGINS_REPO_URL } from "@lib/utils/constants";
|
||||
|
|
@ -41,7 +41,7 @@ async function* getManifests(repoUrl: string) {
|
|||
|
||||
function InstallButton(props: { id: string; }) {
|
||||
const [installed, setInstalled] = useState(isPluginInstalled(props.id));
|
||||
const installationState = useMutation<void, Error, { install: boolean }>({
|
||||
const installationState = useMutation<void, Error, { install: boolean; }>({
|
||||
mutationFn: async ({ install }) => {
|
||||
await (install ? installPlugin : uninstallPlugin)(props.id, true);
|
||||
},
|
||||
|
|
@ -63,11 +63,11 @@ function InstallButton(props: { id: string; }) {
|
|||
/>;
|
||||
}
|
||||
|
||||
function TrailingButtons(props: { id: string }) {
|
||||
function TrailingButtons(props: { id: string; }) {
|
||||
return <Stack spacing={8} direction="horizontal">
|
||||
<IconButton
|
||||
size="sm"
|
||||
onPress={() => {}}
|
||||
onPress={() => { }}
|
||||
variant="secondary"
|
||||
icon={findAssetId("CircleInformationIcon")}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import { useProxy as useNewProxy } from "@lib/api/storage/new";
|
|||
import { showToast } from "@lib/ui/toasts";
|
||||
import { BUNNY_PROXY_PREFIX, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { findByProps } from "@metro";
|
||||
import { NavigationNative, tokens } from "@metro/common";
|
||||
import { Card, FlashList, IconButton, PressableScale, Stack, Text } from "@metro/common/components";
|
||||
|
|
@ -17,9 +16,10 @@ import { ComponentProps } from "react";
|
|||
import { Image, View } from "react-native";
|
||||
|
||||
import unifyVdPlugin from "./models/vendetta";
|
||||
import { isCorePlugin, isPluginInstalled, pluginSettings, registeredPlugins } from "@lib/plugins";
|
||||
import { isCorePlugin, isPluginInstalled, pluginSettings, registeredPlugins } from "@lib/addons/plugins";
|
||||
import unifyBunnyPlugin from "./models/bunny";
|
||||
import { createStyles } from "@lib/ui/styles";
|
||||
import { Author } from "@lib/addons/types";
|
||||
|
||||
const useStyles = createStyles({
|
||||
xButton: {
|
||||
|
|
@ -33,7 +33,7 @@ export interface UnifiedPluginModel {
|
|||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
authors?: Array<Author | string>;
|
||||
authors?: Author;
|
||||
icon?: string;
|
||||
|
||||
isEnabled(): boolean;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { useProxy } from "@lib/api/storage/new";
|
||||
import { disablePlugin, enablePlugin, getId, getPluginSettingsComponent, isPluginEnabled, pluginSettings } from "@lib/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/plugins/types";
|
||||
import { disablePlugin, enablePlugin, getId, getPluginSettingsComponent, isPluginEnabled, pluginSettings } from "@lib/addons/plugins";
|
||||
import { BunnyPluginManifest } from "@lib/addons/plugins/types";
|
||||
|
||||
import { UnifiedPluginModel } from "..";
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ import { formatString, Strings } from "@core/i18n";
|
|||
import { VdPluginManager } from "@core/vendetta/plugins";
|
||||
import { findAssetId } from "@lib/api/assets";
|
||||
import { purgeStorage } from "@lib/api/storage";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { clipboard } from "@metro/common";
|
||||
import { ActionSheet, ActionSheetRow, Button, TableRow, Text } from "@metro/common/components";
|
||||
import { showConfirmationAlert } from "@ui/alerts";
|
||||
import { showConfirmationAlert } from "@core/vendetta/alerts";
|
||||
import { hideSheet } from "@ui/sheets";
|
||||
import { showToast } from "@ui/toasts";
|
||||
import { ScrollView, View } from "react-native";
|
||||
|
|
@ -85,7 +84,7 @@ export default function PluginInfoActionSheet({ plugin, navigation }: PluginInfo
|
|||
content: formatString("ARE_YOU_SURE_TO_CLEAR_DATA", { name: plugin.name }),
|
||||
confirmText: Strings.CLEAR,
|
||||
cancelText: Strings.CANCEL,
|
||||
confirmColor: ButtonColors.RED,
|
||||
confirmColor: "red",
|
||||
onConfirm: async () => {
|
||||
if (vdPlugin.enabled) VdPluginManager.stopPlugin(plugin.id, false);
|
||||
|
||||
|
|
@ -122,7 +121,7 @@ export default function PluginInfoActionSheet({ plugin, navigation }: PluginInfo
|
|||
content: formatString("ARE_YOU_SURE_TO_DELETE_PLUGIN", { name: plugin.name }),
|
||||
confirmText: Strings.DELETE,
|
||||
cancelText: Strings.CANCEL,
|
||||
confirmColor: ButtonColors.RED,
|
||||
confirmColor: "red",
|
||||
onConfirm: () => {
|
||||
try {
|
||||
VdPluginManager.removePlugin(plugin.id);
|
||||
|
|
|
|||
|
|
@ -3,10 +3,9 @@ import AddonCard, { CardWrapper } from "@core/ui/components/AddonCard";
|
|||
import { findAssetId } from "@lib/api/assets";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { applyTheme, fetchTheme, removeTheme, selectTheme, Theme, themes } from "@lib/themes";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { applyTheme, fetchTheme, removeTheme, selectTheme, Theme, themes } from "@lib/addons/themes";
|
||||
import { clipboard } from "@metro/common";
|
||||
import { showConfirmationAlert } from "@ui/alerts";
|
||||
import { showConfirmationAlert } from "@core/vendetta/alerts";
|
||||
import { showToast } from "@ui/toasts";
|
||||
|
||||
function selectAndApply(value: boolean, theme: Theme) {
|
||||
|
|
@ -68,7 +67,7 @@ export default function ThemeCard({ item: theme }: CardWrapper<Theme>) {
|
|||
content: formatString("ARE_YOU_SURE_TO_DELETE_THEME", { name: theme.data.name }),
|
||||
confirmText: Strings.DELETE,
|
||||
cancelText: Strings.CANCEL,
|
||||
confirmColor: ButtonColors.RED,
|
||||
confirmColor: "red",
|
||||
onConfirm: () => {
|
||||
removeTheme(theme.id).then(wasSelected => {
|
||||
setRemoved(true);
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import AddonPage from "@core/ui/components/AddonPage";
|
|||
import ThemeCard from "@core/ui/settings/pages/Themes/ThemeCard";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { useProxy } from "@lib/api/storage";
|
||||
import { installTheme, Theme, themes } from "@lib/themes";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { installTheme, Theme, themes } from "@lib/addons/themes";
|
||||
import { Button } from "@metro/common/components";
|
||||
import { Author } from "@lib/addons/types";
|
||||
|
||||
export default function Themes() {
|
||||
useProxy(settings);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { findByPropsLazy } from "@metro/wrappers";
|
||||
import InputAlert, { InputAlertProps } from "@ui/components/InputAlert";
|
||||
|
||||
|
|
@ -13,7 +12,7 @@ export interface ConfirmationAlertOptions {
|
|||
title?: string;
|
||||
content: string | JSX.Element | (string | JSX.Element)[];
|
||||
confirmText?: string;
|
||||
confirmColor?: ButtonColors;
|
||||
confirmColor?: string;
|
||||
onConfirm: () => void;
|
||||
secondaryConfirmText?: string;
|
||||
onConfirmSecondary?: () => void;
|
||||
|
|
@ -6,15 +6,15 @@ import patcher from "@lib/api/patcher";
|
|||
import { loaderConfig, settings } from "@lib/api/settings";
|
||||
import * as storage from "@lib/api/storage";
|
||||
import { createStorage } from "@lib/api/storage";
|
||||
import * as themes from "@lib/themes";
|
||||
import * as themes from "@lib/addons/themes";
|
||||
import * as utils from "@lib/utils";
|
||||
import { cyrb64Hash } from "@lib/utils/cyrb64";
|
||||
import { DiscordLogger } from "@lib/utils/logger";
|
||||
import { LoggerClass } from "@lib/utils/logger";
|
||||
import * as metro from "@metro";
|
||||
import * as common from "@metro/common";
|
||||
import { Forms } from "@metro/common/components";
|
||||
import * as commonComponents from "@metro/common/components";
|
||||
import * as alerts from "@ui/alerts";
|
||||
import * as alerts from "@core/vendetta/alerts";
|
||||
import * as color from "@ui/color";
|
||||
import * as components from "@ui/components";
|
||||
import { createThemedStyleSheet } from "@ui/styles";
|
||||
|
|
@ -34,7 +34,7 @@ export async function createVdPluginObject(plugin: VendettaPlugin) {
|
|||
// Wrapping this with wrapSync is NOT an option.
|
||||
storage: await createStorage<Record<string, any>>(storage.createMMKVBackend(plugin.id)),
|
||||
},
|
||||
logger: new DiscordLogger(`Bunny » ${plugin.manifest.name}`),
|
||||
logger: new LoggerClass(`Bunny » ${plugin.manifest.name}`),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Author } from "@lib/addons/types";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { awaitStorage, createMMKVBackend, createStorage, purgeStorage, wrapSync } from "@lib/api/storage";
|
||||
import { safeFetch } from "@lib/utils";
|
||||
import { BUNNY_PROXY_PREFIX, VD_PROXY_PREFIX } from "@lib/utils/constants";
|
||||
import { DiscordLogger, logger } from "@lib/utils/logger";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { LoggerClass, logger } from "@lib/utils/logger";
|
||||
|
||||
type EvaledPlugin = {
|
||||
onLoad?(): void;
|
||||
|
|
@ -39,7 +39,9 @@ export const VdPluginManager = {
|
|||
plugins,
|
||||
async pluginFetch(url: string) {
|
||||
if (url.startsWith(VD_PROXY_PREFIX)) {
|
||||
url = url.replace(VD_PROXY_PREFIX, BUNNY_PROXY_PREFIX);
|
||||
url = url
|
||||
.replace("https://bunny-mod.github.io/plugins-proxy", BUNNY_PROXY_PREFIX)
|
||||
.replace(VD_PROXY_PREFIX, BUNNY_PROXY_PREFIX);
|
||||
}
|
||||
|
||||
return await safeFetch(url, { cache: "no-store" });
|
||||
|
|
@ -61,7 +63,7 @@ export const VdPluginManager = {
|
|||
|
||||
if (existingPlugin?.manifest.hash !== pluginManifest.hash) {
|
||||
try {
|
||||
// by polymanifest spec, plugins should always specify their main file, but just in case
|
||||
// by polymanifest spec, plugins should always specify their main file, but just in case
|
||||
pluginJs = await (await this.pluginFetch(id + (pluginManifest.main || "index.js"))).text();
|
||||
} catch { } // Empty catch, checked below
|
||||
}
|
||||
|
|
@ -96,7 +98,7 @@ export const VdPluginManager = {
|
|||
// Wrapping this with wrapSync is NOT an option.
|
||||
storage: await createStorage<Record<string, any>>(createMMKVBackend(plugin.id)),
|
||||
},
|
||||
logger: new DiscordLogger(`Bunny » ${plugin.manifest.name}`),
|
||||
logger: new LoggerClass(`Bunny » ${plugin.manifest.name}`),
|
||||
};
|
||||
const pluginString = `vendetta=>{return ${plugin.js}}\n//# sourceURL=${plugin.id}`;
|
||||
|
||||
|
|
@ -166,7 +168,7 @@ export const VdPluginManager = {
|
|||
const allIds = Object.keys(plugins);
|
||||
|
||||
if (!settings.safeMode?.enabled) {
|
||||
// Loop over any plugin that is enabled, update it if allowed, then start it.
|
||||
// Loop over any plugin that is enabled, update it if allowed, then start it.
|
||||
await Promise.allSettled(allIds.filter(pl => plugins[pl].enabled).map(async pl => (plugins[pl].update && await this.fetchPlugin(pl).catch((e: Error) => logger.error(e.message)), await this.startPlugin(pl))));
|
||||
// Wait for the above to finish, then update all disabled plugins that are allowed to.
|
||||
allIds.filter(pl => !plugins[pl].enabled && plugins[pl].update).forEach(pl => this.fetchPlugin(pl));
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import { patchJSX } from "@lib/api/jsx";
|
|||
import { removeFile, writeFile } from "@lib/api/native/fs";
|
||||
import { isPyonLoader, isThemeSupported } from "@lib/api/native/loader";
|
||||
import { FileManager } from "@lib/api/native/modules";
|
||||
import { updateFonts } from "@lib/fonts";
|
||||
import { initPlugins, registerCorePlugins } from "@lib/plugins";
|
||||
import { initThemes, patchChatBackground } from "@lib/themes";
|
||||
import { updateFonts } from "@lib/addons/fonts";
|
||||
import { initPlugins, registerCorePlugins } from "@lib/addons/plugins";
|
||||
import { initThemes, patchChatBackground } from "@lib/addons/themes";
|
||||
import { logger } from "@lib/utils/logger";
|
||||
import initSafeMode from "@ui/safeMode";
|
||||
import { patchSettings } from "@ui/settings";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { createStorage } from "@lib/api/storage";
|
||||
import { Logger } from "@lib/utils/logger";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { Author } from "../types";
|
||||
|
||||
export interface PluginRepo {
|
||||
[id: string]: {
|
||||
|
|
@ -26,7 +26,7 @@ export interface BunnyPluginManifest {
|
|||
readonly name: string;
|
||||
readonly description: string;
|
||||
readonly version: string;
|
||||
readonly authors: (Author | string)[];
|
||||
readonly authors: Author[];
|
||||
}
|
||||
|
||||
export interface BunnyPluginManifestInternal extends BunnyPluginManifest {
|
||||
|
|
@ -8,12 +8,12 @@ import { after, before, instead } from "@lib/api/patcher";
|
|||
import { awaitStorage, createFileBackend, createMMKVBackend, createStorage, wrapSync } from "@lib/api/storage";
|
||||
import { findInReactTree, safeFetch } from "@lib/utils";
|
||||
import { lazyDestructure, proxyLazy } from "@lib/utils/lazy";
|
||||
import { Author } from "@lib/utils/types";
|
||||
import { byMutableProp } from "@metro/filters";
|
||||
import { createLazyModule } from "@metro/lazy";
|
||||
import { findByNameLazy, findByProps, findByPropsLazy, findByStoreNameLazy } from "@metro/wrappers";
|
||||
import chroma from "chroma-js";
|
||||
import { ImageBackground, Platform, processColor } from "react-native";
|
||||
import { Author } from "../types";
|
||||
|
||||
export interface ThemeData {
|
||||
name: string;
|
||||
4
src/lib/addons/types.ts
Normal file
4
src/lib/addons/types.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
export interface Author {
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import { getImportingModuleId, requireModule } from "@metro/internals/modules";
|
|||
|
||||
// TODO: Deprecate this map, make another that maps to an array of assets (Asset[]) instead
|
||||
/**
|
||||
* @internal
|
||||
* Pitfall: Multiple assets may have the same name, this is fine if we require the asset only for display,\
|
||||
* but not when used to get the registered id/index. In some condition, this would break some plugins like HideGiftButton that gets id by name for patching.\
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ import { getLoaderName, getLoaderVersion, isThemeSupported } from "@lib/api/nati
|
|||
import { BundleUpdaterManager, ClientInfoManager, DeviceManager } from "@lib/api/native/modules";
|
||||
import { after } from "@lib/api/patcher";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { getThemeFromLoader, selectTheme, themes } from "@lib/themes";
|
||||
import { getThemeFromLoader, selectTheme, themes } from "@lib/addons/themes";
|
||||
import { logger } from "@lib/utils/logger";
|
||||
import { showToast } from "@ui/toasts";
|
||||
import { version } from "bunny-build-info";
|
||||
import { Platform, type PlatformConstants } from "react-native";
|
||||
export let socket: WebSocket;
|
||||
|
||||
export interface RNConstants extends PlatformConstants {
|
||||
// Android
|
||||
|
|
@ -44,6 +43,7 @@ export async function toggleSafeMode() {
|
|||
setTimeout(BundleUpdaterManager.reload, 400);
|
||||
}
|
||||
|
||||
let socket: WebSocket;
|
||||
export function connectToDebugger(url: string) {
|
||||
if (socket !== undefined && socket.readyState !== WebSocket.CLOSED) socket.close();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
export * as fs from "./fs";
|
||||
export * as loader from "./loader";
|
||||
export * as modules from "./modules";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Theme } from "@lib/themes";
|
||||
import { Theme } from "@lib/addons/themes";
|
||||
|
||||
// @ts-ignore
|
||||
const pyonLoaderIdentity = globalThis.__PYON_LOADER__;
|
||||
|
|
@ -58,7 +58,7 @@ function polyfillVendettaLoaderIdentity() {
|
|||
const id = getStoredTheme()?.id;
|
||||
if (!id) return null;
|
||||
|
||||
const { themes } = require("@lib/themes");
|
||||
const { themes } = require("@lib/addons/themes");
|
||||
return themes[id] ?? getStoredTheme() ?? null;
|
||||
},
|
||||
configurable: true
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
const nmp = window.nativeModuleProxy;
|
||||
|
||||
/**
|
||||
* A key-value storage based upon `SharedPreferences` on Android.
|
||||
*
|
||||
* These types are based on Android though everything should be the same between
|
||||
* platforms.
|
||||
*/
|
||||
export interface MMKVManager {
|
||||
/**
|
||||
* Get the value for the given `key`, or null
|
||||
* @param key The key to fetch
|
||||
*/
|
||||
getItem: (key: string) => Promise<string | null>;
|
||||
/**
|
||||
* Deletes the value for the given `key`
|
||||
* @param key The key to delete
|
||||
*/
|
||||
removeItem: (key: string) => void;
|
||||
/**
|
||||
* Sets the value of `key` to `value`
|
||||
*/
|
||||
setItem: (key: string, value: string) => void;
|
||||
/**
|
||||
* Goes through every item in storage and returns it, excluding the
|
||||
* keys specified in `exclude`.
|
||||
* @param exclude A list of items to exclude from result
|
||||
*/
|
||||
refresh: (exclude: string[]) => Promise<Record<string, string>>;
|
||||
/**
|
||||
* You will be murdered if you use this function.
|
||||
* Clears ALL of Discord's settings.
|
||||
*/
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export interface FileManager {
|
||||
/**
|
||||
* @param path **Full** path to file
|
||||
*/
|
||||
fileExists: (path: string) => Promise<boolean>;
|
||||
/**
|
||||
* Allowed URI schemes on Android: `file://`, `content://` ([See here](https://developer.android.com/reference/android/content/ContentResolver#accepts-the-following-uri-schemes:_3))
|
||||
*/
|
||||
getSize: (uri: string) => Promise<boolean>;
|
||||
/**
|
||||
* @param path **Full** path to file
|
||||
* @param encoding Set to `base64` in order to encode response
|
||||
*/
|
||||
readFile(path: string, encoding: "base64" | "utf8"): Promise<string>;
|
||||
saveFileToGallery?(uri: string, fileName: string, fileType: "PNG" | "JPEG"): Promise<string>;
|
||||
/**
|
||||
* @param storageDir Either `cache` or `documents`.
|
||||
* @param path Path in `storageDir`, parents are recursively created.
|
||||
* @param data The data to write to the file
|
||||
* @param encoding Set to `base64` if `data` is base64 encoded.
|
||||
* @returns Promise that resolves to path of the file once it got written
|
||||
*/
|
||||
writeFile(storageDir: "cache" | "documents", path: string, data: string, encoding: "base64" | "utf8"): Promise<string>;
|
||||
/**
|
||||
* Removes a file from the path given.
|
||||
* (!) On Android, this always returns false, regardless if it fails or not!
|
||||
* @param storageDir Either `cache` or `documents`
|
||||
* @param path Path to the file to be removed
|
||||
*/
|
||||
removeFile(storageDir: "cache" | "documents", path: string): Promise<unknown>;
|
||||
/**
|
||||
* Clear the folder from the path given
|
||||
* (!) On Android, this only clears all *files* and not subdirectories!
|
||||
* @param storageDir Either `cache` or `documents`
|
||||
* @param path Path to the folder to be cleared
|
||||
* @returns Whether the clearance succeeded
|
||||
*/
|
||||
clearFolder(storageDir: "cache" | "documents", path: string): Promise<boolean>;
|
||||
getConstants: () => {
|
||||
/**
|
||||
* The path the `documents` storage dir (see {@link writeFile}) represents.
|
||||
*/
|
||||
DocumentsDirPath: string;
|
||||
CacheDirPath: string;
|
||||
};
|
||||
/**
|
||||
* Will apparently cease to exist some time in the future so please use {@link getConstants} instead.
|
||||
* @deprecated
|
||||
*/
|
||||
DocumentsDirPath: string;
|
||||
}
|
||||
|
||||
export const MMKVManager = nmp.MMKVManager as MMKVManager;
|
||||
//! 173.10 renamed this to RTNFileManager.
|
||||
export const FileManager = (nmp.DCDFileManager ?? nmp.RTNFileManager) as FileManager;
|
||||
//! 173.13 renamed this to RTNClientInfoManager.
|
||||
export const ClientInfoManager = nmp.InfoDictionaryManager ?? nmp.RTNClientInfoManager;
|
||||
//! 173.14 renamed this to RTNDeviceManager.
|
||||
export const DeviceManager = nmp.DCDDeviceManager ?? nmp.RTNDeviceManager;
|
||||
export const { BundleUpdaterManager } = nmp;
|
||||
export const ThemeManager = nmp.RTNThemeManager ?? nmp.DCDTheme;
|
||||
11
src/lib/api/native/modules/index.ts
Normal file
11
src/lib/api/native/modules/index.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { RNModules } from "./types";
|
||||
|
||||
const nmp = window.nativeModuleProxy;
|
||||
|
||||
export const MMKVManager = nmp.MMKVManager as RNModules.MMKVManager;
|
||||
export const FileManager = (nmp.DCDFileManager ?? nmp.RTNFileManager) as RNModules.FileManager;
|
||||
export const ClientInfoManager = nmp.InfoDictionaryManager ?? nmp.RTNClientInfoManager;
|
||||
export const DeviceManager = nmp.DCDDeviceManager ?? nmp.RTNDeviceManager;
|
||||
export const { BundleUpdaterManager } = nmp;
|
||||
export const ThemeManager = nmp.RTNThemeManager ?? nmp.DCDTheme;
|
||||
|
||||
89
src/lib/api/native/modules/types.ts
Normal file
89
src/lib/api/native/modules/types.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
|
||||
|
||||
export namespace RNModules {
|
||||
/**
|
||||
* A key-value storage based upon `SharedPreferences` on Android.
|
||||
*
|
||||
* These types are based on Android though everything should be the same between
|
||||
* platforms.
|
||||
*/
|
||||
export interface MMKVManager {
|
||||
/**
|
||||
* Get the value for the given `key`, or null
|
||||
* @param key The key to fetch
|
||||
*/
|
||||
getItem: (key: string) => Promise<string | null>;
|
||||
/**
|
||||
* Deletes the value for the given `key`
|
||||
* @param key The key to delete
|
||||
*/
|
||||
removeItem: (key: string) => void;
|
||||
/**
|
||||
* Sets the value of `key` to `value`
|
||||
*/
|
||||
setItem: (key: string, value: string) => void;
|
||||
/**
|
||||
* Goes through every item in storage and returns it, excluding the
|
||||
* keys specified in `exclude`.
|
||||
* @param exclude A list of items to exclude from result
|
||||
*/
|
||||
refresh: (exclude: string[]) => Promise<Record<string, string>>;
|
||||
/**
|
||||
* You will be murdered if you use this function.
|
||||
* Clears ALL of Discord's settings.
|
||||
*/
|
||||
clear: () => void;
|
||||
}
|
||||
|
||||
export interface FileManager {
|
||||
/**
|
||||
* @param path **Full** path to file
|
||||
*/
|
||||
fileExists: (path: string) => Promise<boolean>;
|
||||
/**
|
||||
* Allowed URI schemes on Android: `file://`, `content://` ([See here](https://developer.android.com/reference/android/content/ContentResolver#accepts-the-following-uri-schemes:_3))
|
||||
*/
|
||||
getSize: (uri: string) => Promise<boolean>;
|
||||
/**
|
||||
* @param path **Full** path to file
|
||||
* @param encoding Set to `base64` in order to encode response
|
||||
*/
|
||||
readFile(path: string, encoding: "base64" | "utf8"): Promise<string>;
|
||||
saveFileToGallery?(uri: string, fileName: string, fileType: "PNG" | "JPEG"): Promise<string>;
|
||||
/**
|
||||
* @param storageDir Either `cache` or `documents`.
|
||||
* @param path Path in `storageDir`, parents are recursively created.
|
||||
* @param data The data to write to the file
|
||||
* @param encoding Set to `base64` if `data` is base64 encoded.
|
||||
* @returns Promise that resolves to path of the file once it got written
|
||||
*/
|
||||
writeFile(storageDir: "cache" | "documents", path: string, data: string, encoding: "base64" | "utf8"): Promise<string>;
|
||||
/**
|
||||
* Removes a file from the path given.
|
||||
* (!) On Android, this always returns false, regardless if it fails or not!
|
||||
* @param storageDir Either `cache` or `documents`
|
||||
* @param path Path to the file to be removed
|
||||
*/
|
||||
removeFile(storageDir: "cache" | "documents", path: string): Promise<unknown>;
|
||||
/**
|
||||
* Clear the folder from the path given
|
||||
* (!) On Android, this only clears all *files* and not subdirectories!
|
||||
* @param storageDir Either `cache` or `documents`
|
||||
* @param path Path to the folder to be cleared
|
||||
* @returns Whether the clearance succeeded
|
||||
*/
|
||||
clearFolder(storageDir: "cache" | "documents", path: string): Promise<boolean>;
|
||||
getConstants: () => {
|
||||
/**
|
||||
* The path the `documents` storage dir (see {@link writeFile}) represents.
|
||||
*/
|
||||
DocumentsDirPath: string;
|
||||
CacheDirPath: string;
|
||||
};
|
||||
/**
|
||||
* Will apparently cease to exist some time in the future so please use {@link getConstants} instead.
|
||||
* @deprecated
|
||||
*/
|
||||
DocumentsDirPath: string;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ const syncAwaitSymbol = Symbol.for("vendetta.storage.accessor");
|
|||
|
||||
export function createProxy(target: any = {}): { proxy: any; emitter: Emitter; } {
|
||||
const emitter = new Emitter();
|
||||
const parentTarget = target;
|
||||
|
||||
const childrens = new WeakMap<any, any>();
|
||||
const proxiedChildrenSet = new WeakSet<any>();
|
||||
|
|
|
|||
|
|
@ -2,22 +2,26 @@ import "../global.d.ts"; // eslint-disable-line import-alias/import-alias
|
|||
import "../modules.d.ts"; // eslint-disable-line import-alias/import-alias
|
||||
|
||||
export * as api from "./api";
|
||||
export * as fonts from "./fonts";
|
||||
export * as plugins from "./plugins";
|
||||
export * as themes from "./themes";
|
||||
export * as fonts from "./addons/fonts/index.js";
|
||||
export * as plugins from "./addons/plugins/index.js";
|
||||
export * as themes from "./addons/themes/index.js";
|
||||
export * as ui from "./ui";
|
||||
export * as utils from "./utils";
|
||||
export * as metro from "@metro";
|
||||
|
||||
import * as fonts from "./fonts";
|
||||
import * as plugins from "./plugins";
|
||||
import * as themes from "./themes";
|
||||
import * as fonts from "./addons/fonts/index.js";
|
||||
import * as plugins from "./addons/plugins/index.js";
|
||||
import * as themes from "./addons/themes/index.js";
|
||||
|
||||
/** @internal */
|
||||
export * as _jsx from "react/jsx-runtime";
|
||||
|
||||
import { proxyLazy } from "./utils/lazy";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @deprecated Moved to top level (bunny.*)
|
||||
*/
|
||||
export const managers = proxyLazy(() => {
|
||||
console.warn("bunny.managers.* is deprecated, and moved the top level (bunny.*). bunny.managers will be eventually removed soon");
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { color } from "@lib/themes";
|
||||
import { color } from "@lib/addons/themes";
|
||||
import { constants } from "@metro/common";
|
||||
import { findByStoreNameLazy } from "@metro/wrappers";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { Strings } from "@core/i18n";
|
||||
import { Nullish } from "@lib/utils/types";
|
||||
import { React } from "@metro/common";
|
||||
import { Button, LegacyFormText } from "@metro/common/components";
|
||||
import { Codeblock } from "@ui/components";
|
||||
import { createThemedStyleSheet } from "@ui/styles";
|
||||
import { ScrollView } from "react-native";
|
||||
import { Falsy, ScrollView } from "react-native";
|
||||
|
||||
type ErrorBoundaryState = {
|
||||
hasErr: false;
|
||||
|
|
@ -14,7 +13,7 @@ type ErrorBoundaryState = {
|
|||
};
|
||||
|
||||
export interface ErrorBoundaryProps {
|
||||
children: JSX.Element | Nullish | (JSX.Element | Nullish)[];
|
||||
children: JSX.Element | Falsy | (JSX.Element | Falsy)[];
|
||||
}
|
||||
|
||||
const styles = createThemedStyleSheet({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { LegacyAlert, LegacyFormInput } from "@metro/common/components";
|
||||
import { findByPropsLazy } from "@metro/wrappers";
|
||||
|
||||
|
|
@ -7,7 +6,7 @@ const Alerts = findByPropsLazy("openLazy", "close");
|
|||
export interface InputAlertProps {
|
||||
title?: string;
|
||||
confirmText?: string;
|
||||
confirmColor?: ButtonColors;
|
||||
confirmColor?: string;
|
||||
onConfirm: (input: string) => (void | Promise<void>);
|
||||
cancelText?: string;
|
||||
placeholder?: string;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
export * as wrappers from "./wrappers";
|
||||
|
||||
export { default as Codeblock } from "@ui/components/Codeblock";
|
||||
export { default as ErrorBoundary } from "@ui/components/ErrorBoundary";
|
||||
export { default as Search } from "@ui/components/Search";
|
||||
|
|
|
|||
3
src/lib/ui/components/wrappers/index.ts
Normal file
3
src/lib/ui/components/wrappers/index.ts
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import AlertModal, { AlertActionButton } from "./AlertModal";
|
||||
|
||||
export { AlertModal, AlertActionButton };
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
export * as alerts from "./alerts";
|
||||
export * as color from "./color";
|
||||
export * as components from "./components";
|
||||
export * as settings from "./settings";
|
||||
export * as styles from "./styles";
|
||||
export * as toasts from "./toasts";
|
||||
export * as sheets from "./sheets";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import { DeviceManager } from "@lib/api/native/modules";
|
|||
import { after } from "@lib/api/patcher";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { lazyDestructure } from "@lib/utils/lazy";
|
||||
import { ButtonColors } from "@lib/utils/types";
|
||||
import { Button, CompatButton, SafeAreaView } from "@metro/common/components";
|
||||
import { _lazyContextSymbol } from "@metro/lazy";
|
||||
import { LazyModuleContext } from "@metro/types";
|
||||
|
|
@ -91,7 +90,7 @@ export default () => after.await("render", getErrorBoundaryContext(), function (
|
|||
const buttons: Button[] = [
|
||||
{ text: Strings.RELOAD_DISCORD, onPress: this.handleReload },
|
||||
...!settings.safeMode?.enabled ? [{ text: Strings.RELOAD_IN_SAFE_MODE, onPress: toggleSafeMode }] : [],
|
||||
{ text: Strings.RETRY_RENDER, color: ButtonColors.RED, onPress: () => this.setState({ info: null, error: null }) },
|
||||
{ text: Strings.RETRY_RENDER, color: "red", onPress: () => this.setState({ info: null, error: null }) },
|
||||
];
|
||||
|
||||
return (
|
||||
|
|
@ -130,7 +129,7 @@ export default () => after.await("render", getErrorBoundaryContext(), function (
|
|||
|
||||
return <CompatButton
|
||||
text={button.text}
|
||||
color={button.color ?? ButtonColors.BRAND}
|
||||
color={button.color ?? "brand"}
|
||||
size={button.size ?? "small"}
|
||||
onPress={button.onPress}
|
||||
style={{
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ export interface RowConfig {
|
|||
render?: Parameters<typeof lazy>[0];
|
||||
icon?: ImageURISource | number;
|
||||
usePredicate?: () => boolean,
|
||||
useTrailing?: () => string | JSX.Element,
|
||||
rawTabsConfig?: Record<string, any>;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,18 +13,18 @@ function SettingsSection() {
|
|||
return <>
|
||||
{Object.keys(registeredSections).map(sect => registeredSections[sect].length > 0 && (
|
||||
<LegacyFormSection key={sect} title={sect}>
|
||||
{ /** Is usePredicate here safe? */}
|
||||
{registeredSections[sect].filter(r => r.usePredicate?.() ?? true).map((row, i, arr) => (
|
||||
<>
|
||||
<LegacyFormRow
|
||||
label={row.title()}
|
||||
leading={<LegacyFormIcon source={row.icon} />}
|
||||
trailing={<LegacyFormRow.Arrow label={row.rawTabsConfig?.useTrailing?.() || undefined} />}
|
||||
onPress={wrapOnPress(row.onPress, navigation, row.render, row.title())}
|
||||
/>
|
||||
{i !== arr.length - 1 && <LegacyFormDivider />}
|
||||
</>
|
||||
))}
|
||||
{ /** Is usePredicate here safe? */}
|
||||
{registeredSections[sect].filter(r => r.usePredicate?.() ?? true).map((row, i, arr) => (
|
||||
<>
|
||||
<LegacyFormRow
|
||||
label={row.title()}
|
||||
leading={<LegacyFormIcon source={row.icon} />}
|
||||
trailing={<LegacyFormRow.Arrow label={row.useTrailing?.() || undefined} />}
|
||||
onPress={wrapOnPress(row.onPress, navigation, row.render, row.title())}
|
||||
/>
|
||||
{i !== arr.length - 1 && <LegacyFormDivider />}
|
||||
</>
|
||||
))}
|
||||
</LegacyFormSection>
|
||||
))}
|
||||
</>;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ export function patchTabsUI(unpatches: (() => void | boolean)[]) {
|
|||
title: row.title,
|
||||
icon: row.icon,
|
||||
usePredicate: row.usePredicate,
|
||||
useTrailing: row.useTrailing,
|
||||
onPress: wrapOnPress(row.onPress, null, row.render, row.title()),
|
||||
withArrow: true,
|
||||
...row.rawTabsConfig
|
||||
|
|
|
|||
|
|
@ -1,163 +1,3 @@
|
|||
import { OptionalKeys } from "@lib/utils/types";
|
||||
import { LiteralUnion } from "type-fest";
|
||||
|
||||
export type DiscordTextStyles = OptionalKeys<[
|
||||
"heading-sm/normal",
|
||||
"heading-sm/medium",
|
||||
"heading-sm/semibold",
|
||||
"heading-sm/bold",
|
||||
"heading-sm/extrabold",
|
||||
"heading-md/normal",
|
||||
"heading-md/medium",
|
||||
"heading-md/semibold",
|
||||
"heading-md/bold",
|
||||
"heading-md/extrabold",
|
||||
"heading-lg/normal",
|
||||
"heading-lg/medium",
|
||||
"heading-lg/semibold",
|
||||
"heading-lg/bold",
|
||||
"heading-lg/extrabold",
|
||||
"heading-xl/normal",
|
||||
"heading-xl/medium",
|
||||
"heading-xl/semibold",
|
||||
"heading-xl/bold",
|
||||
"heading-xl/extrabold",
|
||||
"heading-xxl/normal",
|
||||
"heading-xxl/medium",
|
||||
"heading-xxl/semibold",
|
||||
"heading-xxl/bold",
|
||||
"heading-xxl/extrabold",
|
||||
"eyebrow",
|
||||
"heading-deprecated-12/normal",
|
||||
"heading-deprecated-12/medium",
|
||||
"heading-deprecated-12/semibold",
|
||||
"heading-deprecated-12/bold",
|
||||
"heading-deprecated-12/extrabold",
|
||||
"redesign/heading-18/bold",
|
||||
"text-xxs/normal",
|
||||
"text-xxs/medium",
|
||||
"text-xxs/semibold",
|
||||
"text-xxs/bold",
|
||||
"text-xs/normal",
|
||||
"text-xs/medium",
|
||||
"text-xs/semibold",
|
||||
"text-xs/bold",
|
||||
"text-sm/normal",
|
||||
"text-sm/medium",
|
||||
"text-sm/semibold",
|
||||
"text-sm/bold",
|
||||
"text-md/normal",
|
||||
"text-md/medium",
|
||||
"text-md/semibold",
|
||||
"text-md/bold",
|
||||
"text-lg/normal",
|
||||
"text-lg/medium",
|
||||
"text-lg/semibold",
|
||||
"text-lg/bold",
|
||||
"redesign/message-preview/normal",
|
||||
"redesign/message-preview/medium",
|
||||
"redesign/message-preview/semibold",
|
||||
"redesign/message-preview/bold",
|
||||
"redesign/channel-title/normal",
|
||||
"redesign/channel-title/medium",
|
||||
"redesign/channel-title/semibold",
|
||||
"redesign/channel-title/bold",
|
||||
"display-sm",
|
||||
"display-md",
|
||||
"display-lg"
|
||||
]>;
|
||||
|
||||
export type RedesignModuleKeys = OptionalKeys<[
|
||||
"AlertActionButton",
|
||||
"AlertModal",
|
||||
"AlertModalContainer",
|
||||
"AvatarDuoPile",
|
||||
"AvatarPile",
|
||||
"BACKDROP_OPAQUE_MAX_OPACITY",
|
||||
"Backdrop",
|
||||
"Button",
|
||||
"Card",
|
||||
"ContextMenu",
|
||||
"ContextMenuContainer",
|
||||
"FauxHeader",
|
||||
"FloatingActionButton",
|
||||
"GhostInput",
|
||||
"GuildIconPile",
|
||||
"HeaderActionButton",
|
||||
"HeaderButton",
|
||||
"HeaderSubmittingIndicator",
|
||||
"IconButton",
|
||||
"Input",
|
||||
"InputButton",
|
||||
"InputContainer",
|
||||
"LayerContext",
|
||||
"LayerScope",
|
||||
"Modal",
|
||||
"ModalActionButton",
|
||||
"ModalContent",
|
||||
"ModalDisclaimer",
|
||||
"ModalFloatingAction",
|
||||
"ModalFloatingActionSpacer",
|
||||
"ModalFooter",
|
||||
"ModalScreen",
|
||||
"ModalStepIndicator",
|
||||
"NAV_BAR_HEIGHT",
|
||||
"NAV_BAR_HEIGHT_MULTILINE",
|
||||
"Navigator",
|
||||
"NavigatorHeader",
|
||||
"NavigatorScreen",
|
||||
"Pile",
|
||||
"PileOverflow",
|
||||
"RedesignCompat",
|
||||
"RedesignCompatContext",
|
||||
"RowButton",
|
||||
"STATUS_BAR_HEIGHT",
|
||||
"SceneLoadingIndicator",
|
||||
"SearchField",
|
||||
"SegmentedControl",
|
||||
"SegmentedControlPages",
|
||||
"Slider",
|
||||
"Stack",
|
||||
"StepModal",
|
||||
"StickyContext",
|
||||
"StickyHeader",
|
||||
"StickyWrapper",
|
||||
"TABLE_ROW_CONTENT_HEIGHT",
|
||||
"TABLE_ROW_HEIGHT",
|
||||
"TableCheckboxRow",
|
||||
"TableRadioGroup",
|
||||
"TableRadioRow",
|
||||
"TableRow",
|
||||
"TableRowGroup",
|
||||
"TableRowGroupTitle",
|
||||
"TableRowIcon",
|
||||
"TableSwitchRow",
|
||||
"Tabs",
|
||||
"TextArea",
|
||||
"TextField",
|
||||
"TextInput",
|
||||
"Toast",
|
||||
"dismissAlerts",
|
||||
"getHeaderBackButton",
|
||||
"getHeaderCloseButton",
|
||||
"getHeaderConditionalBackButton",
|
||||
"getHeaderNoTitle",
|
||||
"getHeaderTextButton",
|
||||
"hideContextMenu",
|
||||
"navigatorShouldCrossfade",
|
||||
"openAlert",
|
||||
"useAccessibilityNativeStackOptions",
|
||||
"useAndroidNavScrim",
|
||||
"useCoachmark",
|
||||
"useFloatingActionButtonScroll",
|
||||
"useFloatingActionButtonState",
|
||||
"useNativeStackNavigation",
|
||||
"useNavigation",
|
||||
"useNavigationTheme",
|
||||
"useNavigatorBackPressHandler",
|
||||
"useNavigatorScreens",
|
||||
"useNavigatorShouldCrossfade",
|
||||
"useSegmentedControlState",
|
||||
"useStackNavigation",
|
||||
"useTabNavigation",
|
||||
"useTooltip"
|
||||
]>;
|
||||
export type DiscordTextStyles = LiteralUnion<"heading-sm/normal" | "heading-sm/medium" | "heading-sm/semibold" | "heading-sm/bold" | "heading-sm/extrabold" | "heading-md/normal" | "heading-md/medium" | "heading-md/semibold" | "heading-md/bold" | "heading-md/extrabold" | "heading-lg/normal" | "heading-lg/medium" | "heading-lg/semibold" | "heading-lg/bold" | "heading-lg/extrabold" | "heading-xl/normal" | "heading-xl/medium" | "heading-xl/semibold" | "heading-xl/bold" | "heading-xl/extrabold" | "heading-xxl/normal" | "heading-xxl/medium" | "heading-xxl/semibold" | "heading-xxl/bold" | "heading-xxl/extrabold" | "eyebrow" | "heading-deprecated-12/normal" | "heading-deprecated-12/medium" | "heading-deprecated-12/semibold" | "heading-deprecated-12/bold" | "heading-deprecated-12/extrabold" | "redesign/heading-18/bold" | "text-xxs/normal" | "text-xxs/medium" | "text-xxs/semibold" | "text-xxs/bold" | "text-xs/normal" | "text-xs/medium" | "text-xs/semibold" | "text-xs/bold" | "text-sm/normal" | "text-sm/medium" | "text-sm/semibold" | "text-sm/bold" | "text-md/normal" | "text-md/medium" | "text-md/semibold" | "text-md/bold" | "text-lg/normal" | "text-lg/medium" | "text-lg/semibold" | "text-lg/bold" | "redesign/message-preview/normal" | "redesign/message-preview/medium" | "redesign/message-preview/semibold" | "redesign/message-preview/bold" | "redesign/channel-title/normal" | "redesign/channel-title/medium" | "redesign/channel-title/semibold" | "redesign/channel-title/bold" | "display-sm" | "display-md" | "display-lg", string>;
|
||||
|
|
|
|||
|
|
@ -2,13 +2,12 @@ export const DISCORD_SERVER = "https://discord.gg/XjYgWXHb9Q";
|
|||
export const GITHUB = "https://github.com/pyoncord";
|
||||
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;
|
||||
export const VD_PROXY_PREFIX = "https://vd-plugins.github.io/proxy";
|
||||
|
||||
export const BUNNY_PROXY_PREFIX = "https://bn-plugins.github.io/vd-proxy";
|
||||
export const OLD_BUNNY_PROXY_PREFIX = "https://bunny-mod.github.io/plugins-proxy";
|
||||
|
||||
export const OFFICIAL_PLUGINS_REPO_URL = "https://bn-plugins.github.io/dist/repo.json";
|
||||
|
||||
// These are still Vendetta's
|
||||
export const DISCORD_SERVER_ID = "1015931589865246730";
|
||||
export const PLUGINS_CHANNEL_ID = "1091880384561684561";
|
||||
export const THEMES_CHANNEL_ID = "1091880434939482202";
|
||||
export const VD_PROXY_PREFIX = "https://vd-plugins.github.io/proxy";
|
||||
export const VD_DISCORD_SERVER_ID = "1015931589865246730";
|
||||
export const VD_PLUGINS_CHANNEL_ID = "1091880384561684561";
|
||||
export const VD_THEMES_CHANNEL_ID = "1091880434939482202";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Largely inspired by MurmurHash2/3, but with a focus on speed/simplicity.
|
||||
// See https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript/52171480#52171480
|
||||
// https://github.com/bryc/code/blob/master/jshash/experimental/cyrb53.js
|
||||
export function cyrb64(str: string, seed = 0) {
|
||||
export default function cyrb64(str: string, seed = 0) {
|
||||
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
||||
for (let i = 0, ch; i < str.length; i++) {
|
||||
ch = str.charCodeAt(i);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { findInTree } from "@lib/utils";
|
||||
import { SearchFilter } from "@lib/utils/findInTree";
|
||||
|
||||
export const findInReactTree = (tree: { [key: string]: any; }, filter: SearchFilter): any => findInTree(tree, filter, {
|
||||
walkable: ["props", "children", "child", "sibling"],
|
||||
});
|
||||
export default function findInReactTree(tree: { [key: string]: any; }, filter: SearchFilter): any {
|
||||
return findInTree(tree, filter, {
|
||||
walkable: ["props", "children", "child", "sibling"],
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ function treeSearch(tree: SearchTree, filter: SearchFilter, opts: Required<FindI
|
|||
|
||||
try {
|
||||
if (filter(tree)) return tree;
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
if (Array.isArray(tree)) {
|
||||
for (const item of tree) {
|
||||
|
|
@ -24,7 +24,7 @@ function treeSearch(tree: SearchTree, filter: SearchFilter, opts: Required<FindI
|
|||
try {
|
||||
const found = treeSearch(item, filter, opts, depth + 1);
|
||||
if (found) return found;
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
} else if (typeof tree === "object") {
|
||||
for (const key of Object.keys(tree)) {
|
||||
|
|
@ -35,12 +35,12 @@ function treeSearch(tree: SearchTree, filter: SearchFilter, opts: Required<FindI
|
|||
try {
|
||||
const found = treeSearch(tree[key], filter, opts, depth + 1);
|
||||
if (found) return found;
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const findInTree = (
|
||||
export default function findInTree(
|
||||
tree: SearchTree,
|
||||
filter: SearchFilter,
|
||||
{
|
||||
|
|
@ -48,4 +48,6 @@ export const findInTree = (
|
|||
ignore = [],
|
||||
maxDepth = 100
|
||||
}: FindInTreeOptions = {},
|
||||
): any | undefined => treeSearch(tree, filter, { walkable, ignore, maxDepth }, 0);
|
||||
): any | undefined {
|
||||
return treeSearch(tree, filter, { walkable, ignore, maxDepth }, 0);
|
||||
};
|
||||
|
|
@ -2,7 +2,7 @@ import { LiteralUnion } from "type-fest";
|
|||
|
||||
type KeyOfOrAny<P, T extends object> = P extends keyof T ? T[P] : any;
|
||||
|
||||
export function hookDefineProperty<
|
||||
export default function hookDefineProperty<
|
||||
T extends object,
|
||||
P extends LiteralUnion<keyof T, PropertyKey>
|
||||
>(target: T, property: LiteralUnion<keyof T, PropertyKey>, cb: (val: KeyOfOrAny<P, T>) => KeyOfOrAny<P, T>) {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
export * as constants from "./constants";
|
||||
export { cyrb64 } from "./cyrb64";
|
||||
export { Emitter } from "./Emitter";
|
||||
export { findInReactTree } from "./findInReactTree";
|
||||
export { findInTree } from "./findInTree";
|
||||
export { hookDefineProperty } from "./hookDefineProperty";
|
||||
export { default as invariant } from "./invariant";
|
||||
export * as lazy from "./lazy";
|
||||
export * as logger from "./logger";
|
||||
export { safeFetch } from "./safeFetch";
|
||||
import cyrb64 from "./cyrb64";
|
||||
import findInReactTree from "./findInReactTree";
|
||||
import findInTree from "./findInTree";
|
||||
import hookDefineProperty from "./hookDefineProperty";
|
||||
import invariant from "./invariant";
|
||||
import safeFetch from "./safeFetch";
|
||||
|
||||
import * as constants from "./constants";
|
||||
import * as lazy from "./lazy";
|
||||
import * as logger from "./logger";
|
||||
|
||||
export {
|
||||
cyrb64,
|
||||
findInReactTree,
|
||||
findInTree,
|
||||
hookDefineProperty,
|
||||
invariant,
|
||||
safeFetch,
|
||||
|
||||
constants,
|
||||
lazy,
|
||||
logger
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { findByNameLazy } from "@metro/wrappers";
|
||||
|
||||
export type LoggerFunction = (...messages: any[]) => void;
|
||||
type LoggerFunction = (...messages: any[]) => void;
|
||||
export interface Logger {
|
||||
log: LoggerFunction;
|
||||
info: LoggerFunction;
|
||||
|
|
@ -11,5 +11,5 @@ export interface Logger {
|
|||
verbose: LoggerFunction;
|
||||
}
|
||||
|
||||
export const DiscordLogger = findByNameLazy("Logger");
|
||||
export const logger: Logger = new DiscordLogger("Bunny");
|
||||
export const LoggerClass = findByNameLazy("Logger");
|
||||
export const logger: Logger = new LoggerClass("Bunny");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// A really basic fetch wrapper which throws on non-ok response codes
|
||||
export async function safeFetch(input: RequestInfo | URL, options?: RequestInit, timeout = 10000) {
|
||||
export default async function safeFetch(input: RequestInfo | URL, options?: RequestInit, timeout = 10000) {
|
||||
const req = await fetch(input, {
|
||||
signal: timeoutSignal(timeout),
|
||||
...options
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
import { LiteralUnion } from "type-fest";
|
||||
|
||||
export type Nullish = null | undefined;
|
||||
|
||||
export type OptionalKeys<T extends Array<string>> = LiteralUnion<T[number], string>;
|
||||
|
||||
export interface Author {
|
||||
name: string;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export enum ButtonColors {
|
||||
BRAND = "brand",
|
||||
RED = "red",
|
||||
GREEN = "green",
|
||||
PRIMARY = "primary",
|
||||
TRANSPARENT = "transparent",
|
||||
GREY = "grey",
|
||||
LIGHTGREY = "lightgrey",
|
||||
WHITE = "white",
|
||||
LINK = "link"
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
import { Nullish } from "@lib/utils/types";
|
||||
import { DiscordTextStyles } from "@ui/types";
|
||||
import { MutableRefObject, ReactNode, RefObject } from "react";
|
||||
import type * as RN from "react-native";
|
||||
|
|
@ -104,7 +103,7 @@ interface TextInputProps extends Omit<RN.TextInputProps, "onChange" | "onChangeT
|
|||
trailingIcon?: React.FC<any>;
|
||||
trailingPressableProps?: PressableProps;
|
||||
trailingText?: string;
|
||||
value?: string | Nullish;
|
||||
value?: string | RN.Falsy;
|
||||
}
|
||||
|
||||
export type TextInput = React.FC<TextInputProps>;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue